SOPS with Azure KeyVault secret and AKS AAD Pod Identity
SOPS with Azure KeyVault secret and AKS AAD Pod Identity
We want to achieve Gitops with FLUX in Azure AKS, storing the encrypted secrets in git repo using Mozilla’s SOPS.
The obvious problem we have to solve is enable the flux controller pod to decrypt the secrets encrypted using the Azure key vault , we will use the AAD pod Identity for this.
Create the KeyVault , key for SOPS and Managed Identity to access the the key
- Create the azure key vault and cryptographic key to be used by SOPS
- Create a managed identity which flux operator pod will use to decrypt the secrets
-
Add a policy in managed identity for encrypt / decrypt permission for keyvault secret
## Create a Azure KeyVault
1 2 3 4 5
export KEY_VAULT_NAME=bigbang-demo-enbuild export RESOURCE_GROUP_NAME=enbuild-demo export LOCATION=eastus az keyvault create --name $KEY_VAULT_NAME --resource-group $RESOURCE_GROUP_NAME --location $LOCATION
### Create the cryptographic key in KeyVault
1 2 3 4 5
export KEY_VAULT_NAME=bigbang-demo-enbuild export RESOURCE_GROUP_NAME=enbuild-demo export LOCATION=eastus az keyvault key create --name sops-key --vault-name $KEY_VAULT_NAME --protection software --ops encrypt decrypt
## Create a Managed Identity
1 2 3 4 5 6
export RESOURCE_GROUP_NAME=enbuild-demo export LOCATION=eastus az group create -n $RESOURCE_GROUP_NAME -l $LOCATION az identity create -n SopsDecryptorIdentity -g $RESOURCE_GROUP_NAME -l $LOCATION
### Add an access policy for the managed identity created previously
First Obtain the client Id, object Id, and the resource Id of the identity
1 2 3 4 5 6 7 8 9 10 11
export KEY_VAULT_NAME=bigbang-demo-enbuild export RESOURCE_GROUP_NAME=enbuild-demo export LOCATION=eastus CLIENT_ID=$(az identity show -n SopsDecryptorIdentity -g $RESOURCE_GROUP_NAME -o tsv --query "clientId") OBJECT_ID=$(az identity show -n SopsDecryptorIdentity -g $RESOURCE_GROUP_NAME -o tsv --query "principalId") RESOURCE_ID=$(az identity show -n SopsDecryptorIdentity -g $RESOURCE_GROUP_NAME -o tsv --query "id") echo $CLIENT_ID echo $OBJECT_ID echo $RESOURCE_ID
Now add a policy so that managed identity can use the secret for encrypt as well as decrypt sops operation.
1
az keyvault set-policy --name $KEY_VAULT_NAME --resource-group $RESOURCE_GROUP_NAME --object-id $OBJECT_ID --key-permissions encrypt decrypt
Get the key id for future use
1 2 3 4
export KEY_VAULT_NAME=bigbang-demo-enbuild az keyvault key show --name sops-key --vault-name $KEY_VAULT_NAME --query key.kid "https://bigbang-demo-enbuild.vault.azure.net/keys/sops-key/3e7781ddc080466d960d16aa8b520836"
Manually test the SOPS with Azure KeyVault
-
Manually test the encryption using SOPS CLI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
❯ cat sample-secret.yaml data: myuser: anVuZWQK mypassword: VHdpbmUyLURlc3Bpc2UtQnVuaW9uLUFwcmlsLUR1Y2hlc3MtT3B1bGVudGx5 ❯ sops --encrypt --azure-kv https://bigbang-demo-enbuild.vault.azure.net/keys/sops-key/3e7781ddc080466d960d16aa8b520836 sample-secret.yaml > sample-secret-enc.yaml ❯ cat sample-secret-enc.yaml data: myuser: ENC[AES256_GCM,data:TMP9XrpIBtQ=,iv:Dk6fVE1nVoqVxVfC1WlGMowM8s+OAURyw+fZcm/klHM=,tag:5UG7uZPEARVIDDhZgzQqqw==,type:str] mypassword: ENC[AES256_GCM,data:uFRPawEqEsa36jBWyjK0QRTNpAaIwSwr4KDgUD/ZLs2ukSF+Tt9WD99ke6N4slv8OW5SeMG100qdBuU2,iv:rUlunp/WQBacuMEJmlUDZivz2dLTBOVU3CFAa+Yy+2w=,tag:RUMvS9L7IzRrNK5Wrvlkuw==,type:str] sops: kms: [] gcp_kms: [] azure_kv: - vault_url: https://bigbang-demo-enbuild.vault.azure.net name: sops-key version: 3e7781ddc080466d960d16aa8b520836 created_at: "2022-02-18T08:51:56Z" enc: K9WjRTbWa0O5zXC_z0XqLCUh_LdcmsnWz4hEDCrS_5tKS7Q9MhdngyDT6629_Ade4BKfkF8WUUccGdpdjuZsLN8BmD1dmf1kp6YKPxd4uyCNnAIGSbzrvDEtdSkzZw32pK0u7DhwlVmFmdK1nfis89hFxmWVt3L-j4En6dQt8eyzbKqmT2-KsTXFourrpa0h15quItxYswMmxkFNvo5WiNE9zb6pNQUUyNHrQEuGviqlf5Xk-5oK2Nb7PRr85Y_JzmUGlYPaqhhNvo7isbtXl-DP-GIyreM0CVqc4Uzx3CgDtVqVO7z7LkIReGj69SSjBxUOZMRpwdieude5rKrvig hc_vault: [] age: [] lastmodified: "2022-02-18T08:52:00Z" mac: ENC[AES256_GCM,data:6JsIPK3MMyQDlTEob7W4iemOuOaB4VQC4vkJPlIbYqqef2ex9ICirUGsCEf6bOOnvkjsUCUVEEkyZcUludfKPiDusu+Kvl0kResfJuBopaOAcVw3oMWSVVlFbAmELQGXTTLknHAyFY2ImLmYltonhM8bcbabXZRPv+ZDpxVaG4c=,iv:kN6PqLuX3rnENrPYfrrXLwXliXTIP3bv+MBZWIN3DaI=,tag:WAL/fmNHKjML6yMQnuil3A==,type:str] pgp: [] encrypted_regex: ^(data|stringData)$ version: 3.7.1
We can encrypt using config file so that we don’t have to provide the key vault details in CLI
1 2 3 4 5
❯ cat sops.yaml --- creation_rules: - azure_keyvault: 'https://bigbang-demo-enbuild.vault.azure.net/keys/sops-key/3e7781ddc080466d960d16aa8b520836' # encrypted_regex: "^(data|stringData)$"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
❯ sops --config sops.yaml -e sample-secret.yaml > sample-secret-enc.yaml ❯ cat sample-secret-enc.yaml data: myuser: ENC[AES256_GCM,data:TMP9XrpIBtQ=,iv:Dk6fVE1nVoqVxVfC1WlGMowM8s+OAURyw+fZcm/klHM=,tag:5UG7uZPEARVIDDhZgzQqqw==,type:str] mypassword: ENC[AES256_GCM,data:uFRPawEqEsa36jBWyjK0QRTNpAaIwSwr4KDgUD/ZLs2ukSF+Tt9WD99ke6N4slv8OW5SeMG100qdBuU2,iv:rUlunp/WQBacuMEJmlUDZivz2dLTBOVU3CFAa+Yy+2w=,tag:RUMvS9L7IzRrNK5Wrvlkuw==,type:str] sops: kms: [] gcp_kms: [] azure_kv: - vault_url: https://bigbang-demo-enbuild.vault.azure.net name: sops-key version: 3e7781ddc080466d960d16aa8b520836 created_at: "2022-02-18T08:51:56Z" enc: K9WjRTbWa0O5zXC_z0XqLCUh_LdcmsnWz4hEDCrS_5tKS7Q9MhdngyDT6629_Ade4BKfkF8WUUccGdpdjuZsLN8BmD1dmf1kp6YKPxd4uyCNnAIGSbzrvDEtdSkzZw32pK0u7DhwlVmFmdK1nfis89hFxmWVt3L-j4En6dQt8eyzbKqmT2-KsTXFourrpa0h15quItxYswMmxkFNvo5WiNE9zb6pNQUUyNHrQEuGviqlf5Xk-5oK2Nb7PRr85Y_JzmUGlYPaqhhNvo7isbtXl-DP-GIyreM0CVqc4Uzx3CgDtVqVO7z7LkIReGj69SSjBxUOZMRpwdieude5rKrvig hc_vault: [] age: [] lastmodified: "2022-02-18T08:52:00Z" mac: ENC[AES256_GCM,data:6JsIPK3MMyQDlTEob7W4iemOuOaB4VQC4vkJPlIbYqqef2ex9ICirUGsCEf6bOOnvkjsUCUVEEkyZcUludfKPiDusu+Kvl0kResfJuBopaOAcVw3oMWSVVlFbAmELQGXTTLknHAyFY2ImLmYltonhM8bcbabXZRPv+ZDpxVaG4c=,iv:kN6PqLuX3rnENrPYfrrXLwXliXTIP3bv+MBZWIN3DaI=,tag:WAL/fmNHKjML6yMQnuil3A==,type:str] pgp: [] encrypted_regex: ^(data|stringData)$ version: 3.7.1data: myuser: ENC[AES256_GCM,data:TMP9XrpIBtQ=,iv:Dk6fVE1nVoqVxVfC1WlGMowM8s+OAURyw+fZcm/klHM=,tag:5UG7uZPEARVIDDhZgzQqqw==,type:str] mypassword: ENC[AES256_GCM,data:uFRPawEqEsa36jBWyjK0QRTNpAaIwSwr4KDgUD/ZLs2ukSF+Tt9WD99ke6N4slv8OW5SeMG100qdBuU2,iv:rUlunp/WQBacuMEJmlUDZivz2dLTBOVU3CFAa+Yy+2w=,tag:RUMvS9L7IzRrNK5Wrvlkuw==,type:str] sops: kms: [] gcp_kms: [] azure_kv: - vault_url: https://bigbang-demo-enbuild.vault.azure.net name: sops-key version: 3e7781ddc080466d960d16aa8b520836 created_at: "2022-02-18T08:51:56Z" enc: K9WjRTbWa0O5zXC_z0XqLCUh_LdcmsnWz4hEDCrS_5tKS7Q9MhdngyDT6629_Ade4BKfkF8WUUccGdpdjuZsLN8BmD1dmf1kp6YKPxd4uyCNnAIGSbzrvDEtdSkzZw32pK0u7DhwlVmFmdK1nfis89hFxmWVt3L-j4En6dQt8eyzbKqmT2-KsTXFourrpa0h15quItxYswMmxkFNvo5WiNE9zb6pNQUUyNHrQEuGviqlf5Xk-5oK2Nb7PRr85Y_JzmUGlYPaqhhNvo7isbtXl-DP-GIyreM0CVqc4Uzx3CgDtVqVO7z7LkIReGj69SSjBxUOZMRpwdieude5rKrvig hc_vault: [] age: [] lastmodified: "2022-02-18T08:52:00Z" mac: ENC[AES256_GCM,data:6JsIPK3MMyQDlTEob7W4iemOuOaB4VQC4vkJPlIbYqqef2ex9ICirUGsCEf6bOOnvkjsUCUVEEkyZcUludfKPiDusu+Kvl0kResfJuBopaOAcVw3oMWSVVlFbAmELQGXTTLknHAyFY2ImLmYltonhM8bcbabXZRPv+ZDpxVaG4c=,iv:kN6PqLuX3rnENrPYfrrXLwXliXTIP3bv+MBZWIN3DaI=,tag:WAL/fmNHKjML6yMQnuil3A==,type:str] pgp: [] encrypted_regex: ^(data|stringData)$ version: 3.7.1
1 2 3 4
❯ sops -d sample-secret-enc.yaml data: myuser: anVuZWQK mypassword: VHdpbmUyLURlc3Bpc2UtQnVuaW9uLUFwcmlsLUR1Y2hlc3MtT3B1bGVudGx5
Test the secret decryption from AKS POD manually
-
Deploy the AKS or modify existing AKS to enable the pod identity
1
❯ az aks create -g enbuild-demo --node-count 1 -n james-test -k 1.21.7 --enable-managed-identity --enable-pod-identity --enable-pod-identity-with-kubenet
If you are have existing cluster, modify it
1
❯ az aks update -n james-test -g enbuild-demo --enable-managed-identity --enable-pod-identity --enable-pod-identity-with-kubenet
- Add the pod-identity to the AKS cluster in default namespace
1
❯ az aks pod-identity add --resource-group enbuild-demo --cluster-name james-test --name sops --namespace default --identity-resource-id /subscriptions/a36fedae-d136-4bf9-8249-d24d8cbf5f66/resourceGroups/enbuild-demo/providers/Microsoft.ManagedIdentity/userAssignedIdentities/SopsDecryptorIdentity
-
Verify the azureidentity is deployed in default namespace
1 2 3
❯ kubectl get azureidentity NAME AGE sops 119m
-
Create a sample Deployment using sops image and verify the decrypt is working fine.
Make a note in below deployment,
- the namespace is default , as the azureidentity is added in default namespace.
- the sample encrypted file is mounted as config-map
- the deployment label aadpodidbinding is present and set to sops. Since the azureidentity we created is with the name sops.
-
For SOPS cli to work with AAD pod identity we need to set the ENV variable AZURE_AUTH_METHOD and set it to msi
below is the sample deployment file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
--- apiVersion: v1 data: sample-secret-enc.yaml: | data: myuser: ENC[AES256_GCM,data:9SK3Aykc8uo=,iv:HEhUfPpx/uyZBNbySYK5jcfr4o0N7GpvVF2GaryP8Qo=,tag:8qXx/YtoeH7BmH5xJ4IV2w==,type:str] mypassword: ENC[AES256_GCM,data:rlYjZ/EgyPwVsaWUfCMCoslxd5BAWmUoYwjMJR1zaOnUXI2MdzzsqalRabJ7ti7A+BxtogZOoo8dBLkn,iv:2Z/kliSZ33M5vd5mXEst5INRZRYzDOW7PJ8PBFg5+hE=,tag:+/hItGzZraY3tXdINqXMHw==,type:str] sops: kms: [] gcp_kms: [] azure_kv: - vault_url: https://bigbang-demo-enbuild.vault.azure.net name: sops-key version: 3e7781ddc080466d960d16aa8b520836 created_at: "2022-02-18T07:20:12Z" enc: RAlWdd6R9sC5Q7bT22bP4L5VZon79pIcLleARSzNo-wPduFjqlRiFuuUDDbzyzpgj9VxDwHk_KOVAySB3FiOMGKC7SZ0Jgs5pp3NQCSUc86520JOugBfo0Njqp2wCmgfrwiwrBMJUwiK02fkFp1E0Ewc-rNb9DRCdttK1CueR9X70v01w1VDOa4dXJmCz86uByzG-_hW5I7dgDdRh92AztSiCb_f5-HcrKwdc2KJ-rJYIUSIM1bymy_V2w2cvQcejDpvfHbr1Amer9HiKnlqcarOME5L2a2C3HGQRziqb5AI942Vauu4I0cJFQzUmsTQ98sDCO6kYfxN16H8KqNrsA hc_vault: [] age: [] lastmodified: "2022-02-18T07:20:14Z" mac: ENC[AES256_GCM,data:grsvcgSO/WzA1QjlUrWjI2oiDVAYX/Na5ffvxK9DBwXN4DgFxJEWHqPOlOfDWn5BvMKr2Ey9I69x6/chnvsALtdBhDArY5DpJM5HOaTLfuT0CMf1DwvJ8kXanV10B/WRV/YqU6AACbrgJGT15+fDBLO7RbtDolotbEZ+9hjaXtI=,iv:1fC1er/obnmkr2TDUJEv4Ex33f3TuRbgHN0R3Agg3KM=,tag:YKjLsQ/J0k2OfICiLbZSkA==,type:str] pgp: [] encrypted_regex: ^(data|stringData)$ version: 3.7.1 kind: ConfigMap metadata: name: test-secret namespace: default --- apiVersion: apps/v1 kind: Deployment metadata: name: sops-demo namespace: default labels: app: sops-demo spec: replicas: 1 selector: matchLabels: app: sops-demo template: metadata: labels: app: sops-demo aadpodidbinding: sops spec: volumes: # You set volumes at the Pod level, then mount them into containers inside that Pod - name: test-secret configMap: # Provide the name of the ConfigMap you want to mount. name: test-secret # An array of keys from the ConfigMap to create as files items: - key: "sample-secret-enc.yaml" path: "sample-secret-enc.yaml" containers: - name: sops-demo image: mozilla/sops:latest command: ["sops", "-d","/tmp/sample-secret-enc.yaml"] # command: ["sleep","3600"] env: - name: KEYVAULT_NAME value: bigbang-demo-enbuild - name: SECRET_NAME value: Password - name: AZURE_AUTH_METHOD value: msi volumeMounts: - mountPath: /tmp/sample-secret-enc.yaml name: test-secret subPath: sample-secret-enc.yaml
1 2 3 4 5 6 7 8 9 10 11 12
❯ kubectl apply -f deployment.yaml configmap/test-secret unchanged deployment.apps/sops-demo unchanged ❯ kubectl get po NAME READY STATUS RESTARTS AGE sops-demo-7b76486b7-2f9td 0/1 Completed 3 53s ❯ kubectl logs -f sops-demo-7b76486b7-2f9td data: myuser: anVuZWQK mypassword: VHdpbmUyLURlc3Bpc2UtQnVuaW9uLUFwcmlsLUR1Y2hlc3MtT3B1bGVudGx5
Deploy the FLUX and test it GitOps end to end
Since we are going to use AAD Pod Identity , we have to first create the pod-identity in flux-system namespace.
The identity-resource-id is the resource id of the key-vault created before.
1
2
3
❯ kubectl create ns flux-system
❯ az aks pod-identity add --resource-group enbuild-demo --cluster-name james-test --name sops --namespace flux-system --identity-resource-id /subscriptions/a36fedae-d136-4bf9-8249-d24d8cbf5f66/resourceGroups/enbuild-demo/providers/Microsoft.ManagedIdentity/userAssignedIdentities/SopsDecryptorIdentity
Now deploy the flux.
1
2
3
4
5
6
export GITHUB_USER=junaid18183
export GITHUB_REPO=aad-pod-identity-aks-flux-sops-demo
export CLUSTER_NAME=aks
export GITHUB_TOKEN=DUMMYTOKEN
❯ flux bootstrap github --owner=$GITHUB_USER --repository=$GITHUB_REPO --branch=main --path=./clusters/$CLUSTER_NAME
once the flux is deployed we need to patch the kustomize-controller
deployment and add the aadpodidbinding label and AZURE_AUTH_METHOD env variable.
You can use the below kustomization patch to achieve that,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ cat sops-kustomize-patch.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kustomize-controller
namespace: flux-system
spec:
template:
metadata:
labels:
aadpodidbinding: sops # match the AzureIdentityBinding selector
spec:
containers:
- name: manager
env:
- name: AZURE_AUTH_METHOD
value: msi
With this changes in place you can add any encrypted secrets to your gitops and flux will automatically encrypt it.
1
2
3
4
5
6
7
8
❯ cat kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- gotk-components.yaml
- gotk-sync.yaml
patchesStrategicMerge:
- sops-kustomize-patch.yaml