Terraform - App Gateway - Duplicate SSL Certificate Issue - ssl-certificate

I have a Wildcard SSL Certificate in my KeyVault. I've got multiple hostnames that needs to use the Wildcard SSL Certificate for. I want to create 3x HTTPS Listerners in my Application Gateway, each for the different hostnames (hostname1, hostname2 & hostname3). I can use the same certificate for all 3x HTTPS Listerners if I manually create the Listerners in the Azure Portal but once I try to do it via Terraform, it gives me a duplicate SSL Certificate error.
app_gateway.tf
http_listener {
frontend_ip_configuration_name = "AppGWPublicFrontendIP"
frontend_port_name = "fp-443"
host_names = ["${var.ENV}.hostname1.company.com"]
name = "fl-hostname-https-443"
protocol = "Https"
ssl_certificate_name = "star.company.com-cert"
}
http_listener {
frontend_ip_configuration_name = "AppGWPublicFrontendIP"
frontend_port_name = "fp-443"
host_names = ["${var.ENV}.hostname2.company.com"]
name = "fl-hostname2-https-443"
protocol = "Https"
ssl_certificate_name = "star.company.com-cert"
}
http_listener {
frontend_ip_configuration_name = "AppGWPublicFrontendIP"
frontend_port_name = "fp-443"
host_names = ["${var.ENV}.hostname3.company.com"]
name = "fl-hostname3-https-443"
protocol = "Https"
ssl_certificate_name = "star.company.com-cert"
ssl_certificate {
name = "star.company.com-cert"
key_vault_secret_id = "https://keyvault.vault.azure.net/certificates/star-company-com/${var.certificate_secret_id}"
}
Error:
│ Error: updating Application Gateway: (Name "AppGateway_Name" / Resource Group "ResourceGroup_Name"): network.ApplicationGatewaysClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="ApplicationGatewayDuplicateSslCertificate" Message="Application Gateway /subscriptions/00000000-0000-0000-0000-0000000000/resourceGroups/ResourceGroup_Name/providers/Microsoft.Network/applicationGateways/AppGateway_Name cannot have same certificate used across two Ssl Certificate elements. Certificate for /subscriptions/00000000-0000-0000-0000-0000000000/resourceGroups/ResourceGroup_Name/providers/Microsoft.Network/applicationGateways/AppGateway_Name/sslCertificates/cert-***-env-hostname-cert and /subscriptions/00000000-0000-0000-0000-0000000000/resourceGroups/ResourceGroup_Name/providers/Microsoft.Network/applicationGateways/AppGateway_Name/sslCertificates/cert-***-env-hostname-cert are same." Details=[]

You are attempting to create a certificate with the same name as an already-existing certificate, as shown by the error you are seeing. It just needs to be created once, and then referenced in all three HTTP listeners since you're using the same certificate for all three of them.
Here is an updated code sample:
resource "azurerm_key_vault_certificate" "ssl_cert" {
name = "star.company.com-cert"
key_vault_id = azurerm_key_vault.example.id
}
resource "azurerm_application_gateway_http_listener" "http_listeners" {
for_each = {
"hostname1.company.com" = "fl-hostname-https-443",
"hostname2.company.com" = "fl-hostname2-https-443",
"hostname3.company.com" = "fl-hostname3-https-443",
}
name = each.value
resource_group_name = azurerm_resource_group.example.name
application_gateway_name = azurerm_application_gateway.example.name
frontend_ip_configuration_name = azurerm_application_gateway_public_ip.example.name
frontend_port_name = azurerm_application_gateway_frontend_port.example.name
protocol = "Https"
ssl_certificate_name = azurerm_key_vault_certificate.ssl_cert.name
host_names = [each.key]
}
how to retrieve the certificate using the data source, consider the following code:
data "azurerm_key_vault_certificate" "star-company-com" {
name = "star-company-com"
key_vault_id = "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.KeyVault/vaults/<key-vault-name>"
}
resource "azurerm_application_gateway" "example" {
# ...
frontend_port {
name = "https"
port = 443
}
frontend_ip_configuration {
name = "PublicIPAddress"
public_ip_address_id = azurerm_public_ip.example.id
private_ip_address_allocation = "Dynamic"
}
ssl_certificate {
name = "star-company-com"
data = data.azurerm_key_vault_certificate.star-company-com.certificate_data
password = "MyCertPassword"
}
http_listener {
name = "listener1"
frontend_ip_configuration_name = azurerm_application_gateway.example.frontend_ip_configuration[0].name
frontend_port_name = azurerm_application_gateway.example.frontend_port[0].name
protocol = "Https"
ssl_certificate_name = "star-company-com"
}
# ...
}

Related

Issues using certificates in terraform

I'm facing some issues while dealing with certificates in terraform.
Before writing the code below, i've already made a CSR request.
I need to say that certificate_pem and private_key are both encoded in base64, particularly private_key is encrypted.
In the code below, i would like to use private_key and certificate_pem.
resource "kubernetes_secret" "my-secret" {
data = {
"tls.crt" = data.my_data.my-configuration-secret.data["certificate_pem"]
"tls.key" = data.my_data.my-configuration-secret.data["private_key"]
}
metadata {
name = "my-secret"
namespace = "my-namespace"
}
}
Now, in the Ingress ressource, i use this secret name
resource "kubernetes_ingress" "my-sni" {
metadata {
name = "my-sni"
namespace = "my_namespace"
annotations = {
"kubernetes.io/ingress.class" = "my_namespace"
"kubernetes.io/ingress.allow-http" = "true"
"nginx.ingress.kubernetes.io/ssl-redirect" = "false"
"nginx.ingress.kubernetes.io/force-ssl-redirect" = "false"
"nginx.ingress.kubernetes.io/ssl-passthrough" = "false"
"nginx.ingress.kubernetes.io/secure-backends" = "false"
"nginx.ingress.kubernetes.io/proxy-body-size" = "0"
"nginx.ingress.kubernetes.io/proxy-read-timeout" = "3600000"
"nginx.ingress.kubernetes.io/rewrite-target" = "/$1"
"nginx.ingress.kubernetes.io/proxy-send-timeout" = "400000"
"nginx.ingress.kubernetes.io/backend-protocol" = "HTTP"
}
}
spec {
tls {
hosts = ["my_host"]
secret_name = "my-secret"
}
rule {
host = "my_host"
http {
path {
path = "/?(.*)"
backend {
service_name = "my-service"
service_port = 8080
}
}
}
}
}
}
Everything is fine with terraform apply, but i can't go on the host to check if i can access to the microservice.
Someone told me i've to uncypher the private_key.
I don't know how to do that

Module with multiple providers

I have a question regarding the following.
I am using terraform with fortios provider
tree:
these are my providers in the root-prod:
provider "fortios" {
hostname = "xxxxx"
token = "xxxxx"
insecure = "true"
vdom = "PROD"
}
provider "fortios" {
hostname = "xxxx"
token = "xxxx"
insecure = "true"
vdom = "OPS"
alias = "isops"
}
I h got my root-module-prod:
module "AWS_xxx"{
source = "../modules"
name = "AWS_PROD"
prefix_lists = local.aws_prod
providers = {
fortios.dc1 = fortios
fortios.dc2 = fortios.isops
}
}
provider & resource within-child-modules:
terraform {
required_providers {
fortios = {
source = "fortinetdev/fortios"
version = "1.13.1"
configuration_aliases = [ fortios.dc1, fortios.dc2 ]
}
}
}
resource "fortios_router_prefixlist" "prefix_lists" {
name = var.name
dynamic "rule" {
for_each = var.prefix_lists
content {
id = rule.value["id"]
action = rule.value["action"]
prefix = rule.value["prefix"]
ge = rule.value["ge"]
le = rule.value["le"]
}
}
}
my goal is for the above module to create two instances of the resource, one in each of the declared providers.
My issue is that while the resource is created in the first provider PROD it doesn't crated in OPS.
Do you have any clue on this..?
Not really did not work through Terraform-multi-providers.
In our case, I found a way through Jenkins Parallelism.
We launch in parallel multiple envs with the credentials saved encrypted in Jenkins server.

How to configure App Service to use Azure AD login from Terraform

It is easy to Configure a web App Service to use Azure AD login manually via the official document However, How can I achieve this from Terraform? I've searched a while didn't found any examples, if you happen to address one, would be nice to share with me.
The following code is how I created Resource group and provisioned the web application
terraform {
backend "azurerm" {}
}
terraform {
required_version = ">= 0.13"
}
resource "azurerm_resource_group" "tf_resource_group" {
name = "RG_${var.application_name}_${var.environment}"
location = var.location
tags = {
environment = var.environment
DeployedBy = "terraform"
}
}
resource "azurerm_app_service_plan" "tf_service_plan" {
name = "${var.application_name}-${var.environment}-asp"
location = azurerm_resource_group.tf_resource_group.location
resource_group_name = azurerm_resource_group.tf_resource_group.name
kind = "Linux"
reserved = true
sku {
tier = "Standard"
size = "S1"
}
tags = {
environment = var.environment
DeployedBy = "terraform"
}
}
resource "azurerm_app_service" "tf_app_service" {
name = var.application_name
location = azurerm_resource_group.tf_resource_group.location
resource_group_name = azurerm_resource_group.tf_resource_group.name
app_service_plan_id = azurerm_app_service_plan.tf_service_plan.id
site_config {
always_on = true
linux_fx_version = "DOCKER|${var.acr_name}.azurecr.io/${var.img_repo_name}:${var.tag}"
}
app_settings = {
DOCKER_REGISTRY_SERVER_URL = "$DRSRUL"
WEBSITES_ENABLE_APP_SERVICE_STORAGE = "false"
DOCKER_REGISTRY_SERVER_USERNAME = "$ACRNAME"
DOCKER_REGISTRY_SERVER_PASSWORD = "$PW"
}
identity {
type = "SystemAssigned"
}
}
I believe your "azurerm_app_service" resource block needs a auth_settings block with a active_directory block. Example:
auth_settings {
enabled = true
active_directory {
client_id = "${azuread_application.example.application_id}"
}
default_provider = "AzureActiveDirectory"
issuer = "https://sts.windows.net/xxxxxxx-xxxx-xxx-xxxx-xxxtenantID/"

How can I use TLS with Paho MQTT over Javascript?

The code I use currently on my website
var client = null;
var device_is_on = null;
var hostname = "********";
var port = "8003";
var clientId = "mqtt_js_" + parseInt(Math.random() * 100000, 10);
var device_topic = "stat/Device_001/POWER";
var status_topic = "cmnd/Device_001/power";
function connect(){
client = new Paho.MQTT.Client(hostname, Number(port), clientId);
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
var options = {
useSSL: true,
userName : "***",
password : "********",
onSuccess: onConnect,
onFailure: onFail
};
client.connect(options);
}
function onConnect(context) {
options = {qos:0}
client.subscribe(device_topic, options);
client.subscribe(status_topic, options);
var payloadd = "6";
message = new Paho.MQTT.Message(payloadd);
message.destinationName = status_topic;
message.retained = true;
client.send(message);
}
function onFail(context) {
}
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
window.alert("Connection Lost!\nPlease Refresh.");
}
}
function onMessageArrived(message) {
if (message.destinationName == device_topic){
var temperature_heading = document.getElementById("device_display");
temperature_heading.innerHTML = "Air Conditioner: " + message.payloadString;
if (message.payloadString == "ON" || message.payloadString == "o"){
device_is_on = true;
} else {
device_is_on = false;
}
}
}
function device_toggle(){
if (device_is_on){
var payload = "off";
device_is_on = false;
} else {
var payload = "on";
device_is_on = true;
}
message = new Paho.MQTT.Message(payload);
message.destinationName = status_topic;
message.retained = true;
client.send(message);
}
What should I put under the "" var options "" section? currently I am getting the error ERR_CERT_AUTHORITY_INVALID in the console of Google Chrome.
Note 1: This code functions perfectly over http but I am converting to https.
Note 2: I use Mosquitto as my MQTT broker.
Help in much appreciated.
It looks like you are using a self signed certificate. This will not be trusted by your browser so it will not connect, raising the error you have shown.
You have 2 options:
Import the certificate into your browser and mark it as trusted (how you do this will vary depending on what browser you are using). This is only really useful for testing/development because normal users should not be importing random certificates as this opens them up to all kinds of security problems.
Get a real trusted certificate for your website and broker. The simplest/cheapest way to do this will be to use letsencrypt. You can then configure mosquitto to use this certificate.
TLS javascript paho client is available: Github paho.mqtt.javascript/issues/88

Identityserver4 doesn't work by ip address

I've used IdentityServer4 with asp net core Web, all works fine when debug in localhost:50481, but when I use myipaddress:50481 on the same computer and debug mode, it failed. I do not use a temporary credential, instead, I created a RSA cert:
.AddSigningCredential(Config.GetSigningCertificate())
public static RsaSecurityKey GetSigningCertificate()
{
var filename = Path.Combine(Directory.GetCurrentDirectory(), "certificateKey.rsa");
if (File.Exists(filename))
{
var keyFile = File.ReadAllText(filename);
var tempKey = JsonConvert.DeserializeObject<TemporaryRsaKey>(keyFile, new JsonSerializerSettings() { ContractResolver = new RsaKeyContractResolver() });
return CreateRsaSecurityKey(tempKey.Parameters, tempKey.KeyId);
}
else
{
var key = CreateRsaSecurityKey();
RSAParameters parameters;
if (key.Rsa != null)
parameters = key.Rsa.ExportParameters(includePrivateParameters: true);
else
parameters = key.Parameters;
var tempKey = new TemporaryRsaKey
{
Parameters = parameters,
KeyId = key.KeyId
};
File.WriteAllText(filename, JsonConvert.SerializeObject(tempKey, new JsonSerializerSettings() { ContractResolver = new RsaKeyContractResolver() }));
return CreateRsaSecurityKey(tempKey.Parameters, tempKey.KeyId);
}
}
I also checked the jwks of localhost and ipaddress, they are matched.
When I publish the project to local IIS, localhost does not work too, present a 500 Internal error.
all the url in my app is "http://localhost:50481"
I have to say this is a stupid mistake, I have not notice the authConfig,
let config;
if (window.location.hostname === 'localhost') {
config = configForDevelopment;
} else {
config = configForProduction;
}
when I use ip address, the config is switch to prod, change localhost to my ip address make sense.
hope it could others.