diff --git a/dev-infrastructure/configurations/svc-cluster.tmpl.bicepparam b/dev-infrastructure/configurations/svc-cluster.tmpl.bicepparam index baf13e5cc..6ff960752 100644 --- a/dev-infrastructure/configurations/svc-cluster.tmpl.bicepparam +++ b/dev-infrastructure/configurations/svc-cluster.tmpl.bicepparam @@ -48,3 +48,5 @@ param aroDevopsMsiId = '{{ .aroDevopsMsiId }}' param regionalDNSZoneName = '{{ .regionalDNSSubdomain}}.{{ .baseDnsZoneName }}' param regionalResourceGroup = '{{ .regionRG }}' + +param frontendIngressCertName = '{{ .frontend.cert.name }}' diff --git a/dev-infrastructure/templates/svc-cluster.bicep b/dev-infrastructure/templates/svc-cluster.bicep index e8a60cdc1..d545ff494 100644 --- a/dev-infrastructure/templates/svc-cluster.bicep +++ b/dev-infrastructure/templates/svc-cluster.bicep @@ -137,6 +137,9 @@ param aroDevopsMsiId string @description('This is a regional DNS zone') param regionalDNSZoneName string +@description('Frontend Ingress Certificate Name') +param frontendIngressCertName string + var clusterServiceMIName = 'clusters-service' resource serviceKeyVault 'Microsoft.KeyVault/vaults@2024-04-01-preview' existing = { @@ -355,3 +358,18 @@ module eventGrindPrivateEndpoint '../modules/private-endpoint.bicep' = { vnetId: svcCluster.outputs.aksVnetId } } + +// +// C E R T I F I C A T E A C C E S S P E R M I S S I O N +// + +module certificateOfficerAccess '../modules/keyvault/keyvault-secret-access.bicep' = { + name: 'aksClusterKeyVaultSecretsProviderMI-${frontendIngressCertName}' + scope: resourceGroup(serviceKeyVaultResourceGroup) + params: { + keyVaultName: serviceKeyVaultName + roleName: 'Key Vault Secrets User' + managedIdentityPrincipalId: svcCluster.outputs.aksClusterKeyVaultSecretsProviderPrincipalId + secretName: frontendIngressCertName + } +} diff --git a/dev-infrastructure/templates/svc-infra.bicep b/dev-infrastructure/templates/svc-infra.bicep index 67eabe3db..339a5219b 100644 --- a/dev-infrastructure/templates/svc-infra.bicep +++ b/dev-infrastructure/templates/svc-infra.bicep @@ -59,23 +59,3 @@ module clientCertificate '../modules/keyvault/key-vault-cert.bicep' = { issuerName: 'Self' // TODO: Change to OneCertV2-PublicCA when we get the issuer approved. } } - -// -// C E R T I F I C A T E A C C E S S P E R M I S S I O N -// - -resource frontendMSI 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { - name: 'frontend' - location: resourceGroup().location -} - -module certificateOfficerAccess '../modules/keyvault/keyvault-secret-access.bicep' = { - name: 'frontendMI-cert-access-${certName}' - scope: resourceGroup(serviceKeyVaultResourceGroup) - params: { - keyVaultName: serviceKeyVaultName - roleName: 'Key Vault Secrets User' - managedIdentityPrincipalId: frontendMSI.properties.principalId - secretName: certName - } -} diff --git a/frontend/Makefile b/frontend/Makefile index 6cc2528c4..27a7d5b86 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -42,16 +42,25 @@ deploy: FRONTEND_MI_CLIENT_ID=$$(az identity show \ -g ${RESOURCEGROUP} \ -n frontend \ - --query clientId -o tsv);\ + --query clientId -o tsv); \ + SECRET_STORE_MI_CLIENT_ID=$$(az aks show --resource-group ${RESOURCEGROUP} \ + --name ${AKS_NAME} \ + --query addonProfiles.azureKeyvaultSecretsProvider.identity.clientId \ + --output tsv); \ ISTO_VERSION=$$(az aks show -n ${AKS_NAME} -g ${RESOURCEGROUP} --query serviceMeshProfile.istio.revisions[-1] -o tsv) && \ DB_URL=$$(az cosmosdb show -n ${DB_NAME} -g ${RESOURCEGROUP} --query documentEndpoint -o tsv) && \ + TENANT_ID=$(shell az account show --query tenantId --output tsv) && \ kubectl create namespace aro-hcp --dry-run=client -o json | kubectl apply -f - && \ kubectl label namespace aro-hcp "istio.io/rev=$${ISTO_VERSION}" --overwrite=true && \ helm upgrade --install ${HELM_DRY_RUN} aro-hcp-frontend-dev \ deploy/helm/frontend/ \ + --set azure.clientId=$${SECRET_STORE_MI_CLIENT_ID} \ + --set azure.tenantId=$${TENANT_ID} \ --set configMap.databaseName=${DB_NAME} \ --set configMap.databaseUrl="$${DB_URL}" \ --set configMap.frontendMiClientId="$${FRONTEND_MI_CLIENT_ID}" \ + --set credsKeyVault.name=${SERVICE_KEY_VAULT} \ + --set credsKeyVault.secret=${CERTIFICATE_NAME} \ --set serviceAccount.workloadIdentityClientId="$${FRONTEND_MI_CLIENT_ID}" \ --set configMap.currentVersion=${ARO_HCP_FRONTEND_IMAGE} \ --set configMap.location=${LOCATION} \ diff --git a/frontend/deploy/helm/frontend/templates/allow-ingress.authorizationpolicy.yaml b/frontend/deploy/helm/frontend/templates/allow-ingress.authorizationpolicy.yaml new file mode 100644 index 000000000..d3cf0c7ee --- /dev/null +++ b/frontend/deploy/helm/frontend/templates/allow-ingress.authorizationpolicy.yaml @@ -0,0 +1,16 @@ +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-istio-ingress + namespace: aro-hcp +spec: + action: ALLOW + rules: + - from: + - source: + namespaces: ["aks-istio-ingress"] + to: + - operation: + methods: ["GET"] + ports: + - "8443" diff --git a/frontend/deploy/helm/frontend/templates/frontend.gateway.yaml b/frontend/deploy/helm/frontend/templates/frontend.gateway.yaml index ec68d02ec..a1d2ef4c0 100644 --- a/frontend/deploy/helm/frontend/templates/frontend.gateway.yaml +++ b/frontend/deploy/helm/frontend/templates/frontend.gateway.yaml @@ -2,13 +2,17 @@ apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: aro-hcp-gateway-external + namespace: aks-istio-ingress spec: selector: istio: aks-istio-ingressgateway-external servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - "*" + - port: + number: 443 + name: https + protocol: HTTPS + tls: + mode: SIMPLE + credentialName: frontend-credential + hosts: + - "*" diff --git a/frontend/deploy/helm/frontend/templates/frontend.secret-refresher.yaml b/frontend/deploy/helm/frontend/templates/frontend.secret-refresher.yaml new file mode 100644 index 000000000..5bd99bceb --- /dev/null +++ b/frontend/deploy/helm/frontend/templates/frontend.secret-refresher.yaml @@ -0,0 +1,41 @@ +################################ +# +# This keeps the certificate secret fresh because the secret is mounted from the keyVault (via the SecretProviderClass) and +# it's if the certificate changes in the keyvault this will trigger the refreshing of the kubernetes secret. +# +# Note: the istio plugin doesn't support using the SecretProviderClass directly. When it does this can be removed. +# +################################ + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend-certificate-refresher + namespace: aks-istio-ingress +spec: + replicas: 1 + selector: + matchLabels: + app: frontend-certificate-refresher + template: + metadata: + labels: + app: frontend-certificate-refresher + spec: + containers: + - command: + - "/bin/sleep" + - "10" + image: busybox + name: init-container-msg-container-init + volumeMounts: + - name: secrets-store01-inline + mountPath: "/mnt/secrets-store" + readOnly: true + volumes: + - name: secrets-store01-inline + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "frontend-scp" diff --git a/frontend/deploy/helm/frontend/templates/frontend.secretproviderclass.yaml b/frontend/deploy/helm/frontend/templates/frontend.secretproviderclass.yaml new file mode 100644 index 000000000..07aadd2b9 --- /dev/null +++ b/frontend/deploy/helm/frontend/templates/frontend.secretproviderclass.yaml @@ -0,0 +1,34 @@ +################################ +# +# The addition of the secretObjects is to facilitate the istio plugin as it can't yet consume the SecretProviderClass directly. +# When it does this can be simplified and the secret.refresher removed. +# +################################ + +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: frontend-scp + namespace: aks-istio-ingress +spec: + parameters: + usePodIdentity: "false" + useVMManagedIdentity: "true" + userAssignedIdentityID: {{ .Values.azure.clientId}} + keyvaultName: {{ .Values.credsKeyVault.name }} + objects: |- + array: + - | + objectName: {{ .Values.credsKeyVault.secret }} + objectType: secret + objectAlias: frontend-cert + tenantId: {{ .Values.azure.tenantId }} + provider: azure + secretObjects: + - secretName: frontend-credential + type: kubernetes.io/tls + data: + - objectName: frontend-cert + key: tls.crt + - objectName: frontend-cert + key: tls.key diff --git a/frontend/deploy/helm/frontend/templates/frontend.virtualservice.yaml b/frontend/deploy/helm/frontend/templates/frontend.virtualservice.yaml index e79caff25..5a3290147 100644 --- a/frontend/deploy/helm/frontend/templates/frontend.virtualservice.yaml +++ b/frontend/deploy/helm/frontend/templates/frontend.virtualservice.yaml @@ -2,14 +2,16 @@ apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: aro-hcp-vs-frontend + namespace: {{ .Release.Namespace }} spec: hosts: - "*" gateways: - - aro-hcp-gateway-external + - aks-istio-ingress/aro-hcp-gateway-external http: - match: - - port: 80 + - uri: + regex: '.+' route: - destination: host: aro-hcp-frontend diff --git a/frontend/deploy/helm/frontend/values.yaml b/frontend/deploy/helm/frontend/values.yaml index 8f71f75d5..220d956f1 100644 --- a/frontend/deploy/helm/frontend/values.yaml +++ b/frontend/deploy/helm/frontend/values.yaml @@ -1,9 +1,15 @@ +azure: + clientId: "" + tenantId: "" configMap: databaseUrl: "" frontendMiClientId: "" currentVersion: "" databaseName: "" location: "" +credsKeyVault: + name: "" + secret: "" deployment: imageName: "" serviceAccount: diff --git a/frontend/pipeline.yaml b/frontend/pipeline.yaml index 9a90851e2..f674f7e0c 100644 --- a/frontend/pipeline.yaml +++ b/frontend/pipeline.yaml @@ -26,3 +26,7 @@ resourceGroups: configRef: frontend.cosmosDB.name - name: COMMIT configRef: frontend.imageTag + - name: SERVICE_KEY_VAULT + configRef: serviceKeyVault.name + - name: CERTIFICATE_NAME + configRef: frontend.cert.name