diff --git a/bicep/modules/blade_configuration.bicep b/bicep/modules/blade_configuration.bicep index 6d96b6bc..21a3185d 100644 --- a/bicep/modules/blade_configuration.bicep +++ b/bicep/modules/blade_configuration.bicep @@ -410,9 +410,8 @@ values.yaml: | appOid: {7} resourceGroup: {8} storageAccountName: {11} - subscription: {12} - aksName: {13} - dnsName: {14} + region: {12} + dnsName: {13} ingress: internalGateway: enabled: {9} @@ -459,8 +458,7 @@ module appConfigMap './aks-config-map/main.bicep' = { clusterIngress == 'Internal' || clusterIngress == 'Both' ? 'true' : 'false', clusterIngress == 'External' || clusterIngress == 'Both' ? 'true' : 'false', storageAccountName, - subscription().subscriptionId, - clusterName, + location, dnsName) ] } diff --git a/charts/dns-configuration/templates/clusterrole.yaml b/charts/dns-configuration/templates/clusterrole.yaml deleted file mode 100644 index b63b2aab..00000000 --- a/charts/dns-configuration/templates/clusterrole.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: dns-config-job-cluster-reader -rules: -- apiGroups: [""] - resources: ["services"] - verbs: ["get", "list", "watch"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: dns-config-job-cluster-reader-binding -subjects: -- kind: ServiceAccount - name: workload-identity-sa - namespace: {{ .Release.Namespace }} -roleRef: - kind: ClusterRole - name: dns-config-job-cluster-reader - apiGroup: rbac.authorization.k8s.io diff --git a/charts/dns-configuration/templates/configmap.yaml b/charts/dns-configuration/templates/configmap.yaml deleted file mode 100644 index 44b34260..00000000 --- a/charts/dns-configuration/templates/configmap.yaml +++ /dev/null @@ -1,144 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "dns-configuration.fullname" . }}-script - namespace: {{ .Release.Namespace }} - labels: - {{- include "dns-configuration.labels" . | nindent 4 }} -data: - configure-dns.sh: | - #!/bin/bash - set -euo pipefail - - echo "=================================================================" - echo " Starting DNS Configuration for AKS LoadBalancer" - echo "=================================================================" - - # Function to install kubectl - install_kubectl() { - echo "Installing kubectl..." - curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x kubectl - mv kubectl /usr/local/bin/ - kubectl version --client - } - - # Function to login to Azure - login_azure() { - echo "Logging into Azure with workload identity..." - az login --federated-token "$(cat ${AZURE_FEDERATED_TOKEN_FILE})" \ - --service-principal \ - -u ${AZURE_CLIENT_ID} \ - -t ${AZURE_TENANT_ID} \ - --allow-no-subscriptions - - az account set --subscription ${AZURE_SUBSCRIPTION} - echo "Azure login successful" - } - - # Function to wait for LoadBalancer IP - wait_for_loadbalancer() { - echo "Waiting for LoadBalancer IP from ${ISTIO_SERVICE_NAME} in ${ISTIO_NAMESPACE}..." - local retry_count=0 - - while [ $retry_count -lt $MAX_RETRIES ]; do - EXTERNAL_IP=$(kubectl get svc ${ISTIO_SERVICE_NAME} \ - -n ${ISTIO_NAMESPACE} \ - -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || echo "") - - if [ -n "$EXTERNAL_IP" ]; then - echo "External IP obtained: $EXTERNAL_IP" - return 0 - fi - - echo "External IP not ready. Retrying in ${RETRY_INTERVAL}s... (Attempt $((retry_count + 1))/$MAX_RETRIES)" - sleep $RETRY_INTERVAL - retry_count=$((retry_count + 1)) - done - - echo "ERROR: Failed to get external IP after $MAX_RETRIES attempts" - return 1 - } - - # Function to configure DNS - configure_dns() { - echo "Configuring DNS for IP: $EXTERNAL_IP" - - # Get node resource group - NODE_RG=$(az aks show --resource-group ${RESOURCE_GROUP} --name ${AKS_NAME} --query nodeResourceGroup -o tsv) - echo "Node Resource Group: $NODE_RG" - - # Find public IP resource - IP_NAME=$(az network public-ip list --resource-group $NODE_RG --query "[?ipAddress=='$EXTERNAL_IP'].name" -o tsv) - - if [ -z "$IP_NAME" ]; then - echo "ERROR: Could not find public IP resource for $EXTERNAL_IP" - return 1 - fi - - echo "Public IP Resource: $IP_NAME" - - # Set DNS label to DNS_NAME only - DNS_LABEL="${DNS_NAME}" - echo "Setting DNS label: $DNS_LABEL" - - az network public-ip update \ - --resource-group $NODE_RG \ - --name $IP_NAME \ - --dns-name $DNS_LABEL - - # Get FQDN - LOCATION=$(az network public-ip show \ - --resource-group $NODE_RG \ - --name $IP_NAME \ - --query location -o tsv) - - FQDN=$(az network public-ip show \ - --resource-group $NODE_RG \ - --name $IP_NAME \ - --query dnsSettings.fqdn -o tsv) - - if [ -z "$FQDN" ] || [ "$FQDN" == "null" ]; then - FQDN="${DNS_LABEL}.${LOCATION}.cloudapp.azure.com" - fi - - echo "FQDN: $FQDN" - } - # Function to create ConfigMap - create_configmap() { - echo "Creating ConfigMap with DNS information..." - - CURRENT_NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) - kubectl create configmap dns-config \ - --from-literal=external_ip=$EXTERNAL_IP \ - --from-literal=fqdn=$FQDN \ - --from-literal=dns_label=$DNS_LABEL \ - --namespace=$CURRENT_NAMESPACE \ - --dry-run=client -o yaml | kubectl apply -f - - echo "ConfigMap created in $CURRENT_NAMESPACE namespace" - kubectl get configmap dns-config -n $CURRENT_NAMESPACE - } - - # Main execution - echo "Starting DNS configuration process..." - - install_kubectl - login_azure - - if ! wait_for_loadbalancer; then - exit 1 - fi - - if ! configure_dns; then - exit 1 - fi - - create_configmap - - echo "=================================================================" - echo " DNS Configuration Completed Successfully" - echo "=================================================================" - echo "FQDN: $FQDN" - echo "External IP: $EXTERNAL_IP" - echo "DNS Label: $DNS_LABEL" - echo "=================================================================" \ No newline at end of file diff --git a/charts/dns-configuration/templates/job.yaml b/charts/dns-configuration/templates/job.yaml deleted file mode 100644 index 95cc2c9d..00000000 --- a/charts/dns-configuration/templates/job.yaml +++ /dev/null @@ -1,73 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ include "dns-configuration.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "dns-configuration.labels" . | nindent 4 }} -spec: - ttlSecondsAfterFinished: 300 - backoffLimit: 3 - template: - metadata: - labels: - {{- include "dns-configuration.selectorLabels" . | nindent 8 }} - azure.workload.identity/use: "true" - spec: - serviceAccountName: {{ include "dns-configuration.serviceAccountName" . }} - restartPolicy: Never - volumes: - - name: script - configMap: - name: {{ include "dns-configuration.fullname" . }}-script - defaultMode: 0755 - - name: azure-identity-token - projected: - sources: - - serviceAccountToken: - path: azure-identity-token - expirationSeconds: 3600 - audience: api://AzureADTokenExchange - containers: - - name: dns-config - image: "mcr.microsoft.com/azure-cli:latest" - imagePullPolicy: IfNotPresent - command: ["/scripts/configure-dns.sh"] - volumeMounts: - - name: script - mountPath: /scripts - - name: azure-identity-token - mountPath: /var/run/secrets/azure/tokens - readOnly: true - resources: - limits: - memory: 512Mi - cpu: 500m - requests: - memory: 256Mi - cpu: 100m - env: - - name: AZURE_CLIENT_ID - value: {{ .Values.azure.clientId | quote }} - - name: AZURE_TENANT_ID - value: {{ .Values.azure.tenantId | quote }} - - name: AZURE_SUBSCRIPTION - value: {{ .Values.azure.subscription | quote }} - - name: AZURE_FEDERATED_TOKEN_FILE - value: /var/run/secrets/azure/tokens/azure-identity-token - - name: RESOURCE_GROUP - value: {{ .Values.azure.resourceGroup | quote }} - - name: AKS_NAME - value: {{ .Values.azure.aksName | quote }} - - name: DNS_NAME - value: {{ .Values.azure.dnsName | quote }} - - name: MAX_RETRIES - value: "60" - - name: RETRY_INTERVAL - value: "10" - - name: ISTIO_SERVICE_NAME - value: "istio-ingress-external" - - name: ISTIO_NAMESPACE - value: "istio-system" - - name: AZURE_AUTHORITY_HOST - value: "https://login.microsoftonline.com/" \ No newline at end of file diff --git a/charts/dns-configuration/templates/role-configmap.yaml b/charts/dns-configuration/templates/role-configmap.yaml deleted file mode 100644 index 7cfb88d4..00000000 --- a/charts/dns-configuration/templates/role-configmap.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: dns-configmap-manager - namespace: {{ .Release.Namespace }} -rules: - - apiGroups: [""] - resources: ["configmaps"] - verbs: ["get", "create", "update", "patch"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: dns-configmap-manager-binding - namespace: {{ .Release.Namespace }} -subjects: - - kind: ServiceAccount - name: workload-identity-sa - namespace: {{ .Release.Namespace }} -roleRef: - kind: Role - name: dns-configmap-manager - apiGroup: rbac.authorization.k8s.io diff --git a/charts/dns-configuration/values.yaml b/charts/dns-configuration/values.yaml deleted file mode 100644 index c5d5ee8b..00000000 --- a/charts/dns-configuration/values.yaml +++ /dev/null @@ -1,28 +0,0 @@ - -# Default values for dns-configuration - -################################################################################ -# Chart name overrides -# -nameOverride: "" -fullnameOverride: "" - -################################################################################ -# Service account for workload identity -# -serviceAccount: - create: false - # The name of the service account to use. - # If create is false, a service account with this name must already exist - name: "workload-identity-sa" - -################################################################################ -# Azure environment specific values -# -azure: - tenantId: # Azure tenant ID - clientId: # Managed identity client ID - subscription: # Azure subscription ID - resourceGroup: # Resource group containing the AKS cluster - aksName: # AKS cluster name - dnsName: "" # Unique ID for the cluster diff --git a/charts/dns-configuration/Chart.yaml b/charts/istio-certs/Chart.yaml similarity index 96% rename from charts/dns-configuration/Chart.yaml rename to charts/istio-certs/Chart.yaml index 2a136158..35ae8c95 100644 --- a/charts/dns-configuration/Chart.yaml +++ b/charts/istio-certs/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -name: dns-configuration +name: istio-certs description: A Helm chart for configuring DNS labels on AKS LoadBalancer IPs # A chart can be either an 'application' or a 'library' chart. diff --git a/charts/dns-configuration/README.md b/charts/istio-certs/README.md similarity index 61% rename from charts/dns-configuration/README.md rename to charts/istio-certs/README.md index 1fb2f06e..850a8f7d 100644 --- a/charts/dns-configuration/README.md +++ b/charts/istio-certs/README.md @@ -1,45 +1,33 @@ -# DNS Configuration Helm Chart +# Istio Certs Helm Chart This chart configures DNS labels for Azure Kubernetes Service (AKS) LoadBalancer IPs, enabling automatic FQDN assignment for OSDU services. -------------------------------------------------------------------------------- + ## Prerequisites -- Azure Kubernetes Service (AKS) cluster with workload identity enabled +- Azure Kubernetes Service (AKS) cluster - Istio service mesh deployed -- Azure CLI and kubectl access configured +- kubectl access configured -------------------------------------------------------------------------------- -## Install Process - -Either manually modify the `values.yaml` for the chart or generate a `custom_values.yaml` to use. - -_The following commands can help generate a prepopulated custom values file._ -```bash -# Setup Variables -GROUP= +## Install Process -SUBSCRIPTION=$(az account show --query id -otsv) -AKS_NAME=$(az aks list --resource-group $GROUP --query "[0].name" -otsv) +Modify the `values.yaml` for the chart or create a `custom_values.yaml` with the following required values: -cat > custom_values.yaml << EOF -################################################################################ -# Azure environment specific values -# +```yaml azure: - tenantId: $(az account show --query tenantId -otsv) - clientId: $(az identity list --resource-group $GROUP --query "[?contains(name, 'osdu-identity')].clientId" -otsv) - configEndpoint: $(az appconfig list --resource-group $GROUP --query "[0].endpoint" -otsv) - keyvaultName: $(az keyvault list --resource-group $GROUP --query "[0].name" -otsv) - keyvaultUri: $(az keyvault list --resource-group $GROUP --query "[0].properties.vaultUri" -otsv) - subscription: $SUBSCRIPTION - resourceGroup: $GROUP - aksName: $AKS_NAME -EOF + region: # Azure region, e.g. eastus + dnsName: # Unique DNS label for the cluster +istioServiceName: istio-ingressgateway # Name of the Istio service +istioNamespace: istio-system # Namespace of the Istio service +maxRetries: 30 # Max retries for waiting on LoadBalancer IP +retryInterval: 10 # Seconds between retries ``` -------------------------------------------------------------------------------- + ## Manual Testing Test the chart locally: @@ -91,11 +79,6 @@ kubectl delete configmap dns-config -n $NAMESPACE |--------------------------|------------------------------------------|------------------------| | `serviceAccount.create` | Create a new service account | `false` | | `serviceAccount.name` | Service account name to use | `workload-identity-sa` | -| `azure.tenantId` | Azure tenant ID | `` | -| `azure.clientId` | Azure client ID for workload identity | `` | -| `azure.subscription` | Azure subscription ID | `` | -| `azure.resourceGroup` | Resource group containing the AKS cluster| `` | -| `azure.aksName` | AKS cluster name | `` | | `azure.uniqueId` | Unique ID for the cluster | `""` | -------------------------------------------------------------------------------- diff --git a/charts/dns-configuration/templates/_helpers.tpl b/charts/istio-certs/templates/_helpers.tpl similarity index 100% rename from charts/dns-configuration/templates/_helpers.tpl rename to charts/istio-certs/templates/_helpers.tpl diff --git a/charts/istio-certs/templates/access_control.yaml b/charts/istio-certs/templates/access_control.yaml new file mode 100644 index 00000000..0a8b0d69 --- /dev/null +++ b/charts/istio-certs/templates/access_control.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-ingress-external-dns + namespace: istio-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: istio-ingress-external-manager + namespace: istio-system +rules: + - apiGroups: [""] + resources: ["services"] + verbs: ["get", "patch", "update"] + - apiGroups: ["cert-manager.io"] + resources: ["certificates"] + verbs: ["get", "create", "update", "patch", "apply"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-ingress-external-binding + namespace: istio-system +subjects: + - kind: ServiceAccount + name: istio-ingress-external-dns + namespace: istio-system +roleRef: + kind: Role + name: istio-ingress-external-manager + apiGroup: rbac.authorization.k8s.io diff --git a/charts/istio-certs/templates/configmap.yaml b/charts/istio-certs/templates/configmap.yaml new file mode 100644 index 00000000..20615f0d --- /dev/null +++ b/charts/istio-certs/templates/configmap.yaml @@ -0,0 +1,80 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "dns-configuration.fullname" . }}-script + namespace: {{ .Release.Namespace }} + labels: + {{- include "dns-configuration.labels" . | nindent 4 }} +data: + configure-dns.sh: | + #!/usr/bin/env bash + set -euo pipefail + + echo "=================================================================" + echo " Starting DNS + Cert Configuration for AKS LoadBalancer" + echo "=================================================================" + + install_kubectl() { + echo "Installing kubectl…" + tdnf install -y ca-certificates + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x kubectl && mv kubectl /usr/local/bin/ + } + + wait_for_loadbalancer_ip() { + echo "Waiting for LoadBalancer IP on service istio-ingress-external in istio-system..." + for ((i=0; i<60; i++)); do + EXTERNAL_IP=$(kubectl get svc istio-ingress-external -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || :) + if [[ -n "$EXTERNAL_IP" ]]; then + echo "Found IP: $EXTERNAL_IP" + return 0 + fi + echo "…retry $((i+1))/60" + sleep 5 + done + echo "ERROR: LoadBalancer IP not assigned after 60 attempts." + return 1 + } + + annotate_service_with_dns() { + echo "Annotating service with DNS label ${DNS_NAME}..." + kubectl annotate svc istio-ingress-external -n istio-system \ + service.beta.kubernetes.io/azure-dns-label-name="${DNS_NAME}" --overwrite + } + + apply_certificate() { + FQDN="${DNS_NAME}.${AZURE_REGION}.cloudapp.azure.com" + echo "Using FQDN: $FQDN" + echo "Applying cert-manager Certificate for $FQDN" + sed "s/__FQDN__/$FQDN/g" /scripts/istio-certificate.yaml | kubectl apply -f - + echo "✔ Certificate applied for ${FQDN}" + } + + main() { + install_kubectl + wait_for_loadbalancer_ip + annotate_service_with_dns + apply_certificate + } + + main "$@" + + istio-certificate.yaml: | + apiVersion: cert-manager.io/v1 + kind: Certificate + metadata: + name: istio-ingressgateway-certs + namespace: istio-system + spec: + secretName: istio-ingressgateway-certs + duration: 2160h # 90 days + renewBefore: 360h # 15 days + subject: + organizations: + - Example Organization + commonName: __FQDN__ + dnsNames: + - __FQDN__ + issuerRef: + name: letsencrypt-staging + kind: ClusterIssuer diff --git a/charts/istio-certs/templates/job.yaml b/charts/istio-certs/templates/job.yaml new file mode 100644 index 00000000..bf8b83f6 --- /dev/null +++ b/charts/istio-certs/templates/job.yaml @@ -0,0 +1,47 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "dns-configuration.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "dns-configuration.labels" . | nindent 4 }} +spec: + ttlSecondsAfterFinished: 300 + backoffLimit: 3 + template: + metadata: + labels: + {{- include "dns-configuration.selectorLabels" . | nindent 8 }} + azure.workload.identity/use: "true" + spec: + serviceAccountName: istio-ingress-external-dns + restartPolicy: Never + volumes: + - name: script + configMap: + name: {{ include "dns-configuration.fullname" . }}-script + defaultMode: 0755 + containers: + - name: dns-config + image: "mcr.microsoft.com/cbl-mariner/base/core:2.0" + imagePullPolicy: IfNotPresent + command: ["/scripts/configure-dns.sh"] + volumeMounts: + - name: script + mountPath: /scripts + resources: + limits: + memory: 512Mi + cpu: 500m + requests: + memory: 256Mi + cpu: 100m + env: + - name: DNS_NAME + value: {{ .Values.azure.dnsName | quote }} + - name: AZURE_REGION + value: {{ .Values.azure.region | quote }} + - name: MAX_RETRIES + value: "60" + - name: RETRY_INTERVAL + value: "5" \ No newline at end of file diff --git a/charts/istio-certs/values.yaml b/charts/istio-certs/values.yaml new file mode 100644 index 00000000..199684be --- /dev/null +++ b/charts/istio-certs/values.yaml @@ -0,0 +1,24 @@ + +# Default values for dns-configuration + +################################################################################ +# Chart name overrides +# +nameOverride: "" +fullnameOverride: "" + + +################################################################################ +# Azure environment specific values +# +azure: + region: # Azure region, e.g. eastus + dnsName: "" # DNS name to be used for the LoadBalancer IP + +################################################################################ +# Istio configuration values +# +istioServiceName: "istio-ingressgateway" # Name of the Istio service +istioNamespace: "istio-system" # Namespace of the Istio service +maxRetries: 30 # Max retries for waiting on LoadBalancer IP +retryInterval: 10 # Seconds between retries diff --git a/software/components/osdu-system/dns.yaml b/software/components/mesh-ingress/certs.yaml similarity index 79% rename from software/components/osdu-system/dns.yaml rename to software/components/mesh-ingress/certs.yaml index ca730c02..6f36e0d8 100644 --- a/software/components/osdu-system/dns.yaml +++ b/software/components/mesh-ingress/certs.yaml @@ -1,16 +1,16 @@ apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: - name: dns-configuration + name: istio-certs namespace: default spec: - targetNamespace: osdu-system + targetNamespace: istio-system dependsOn: - name: istio-ingress-external namespace: flux-system chart: spec: - chart: ./charts/dns-configuration + chart: ./charts/istio-certs sourceRef: kind: GitRepository name: flux-system