All Projects → HoussemDellai → aks-keyvault

HoussemDellai / aks-keyvault

Licence: other
Access Azure Key Vault secrets, keys and certs from AKS Pods using Secret Store CSI provider and Pod Identity.

Programming Languages

powershell
5483 projects
shell
77523 projects

Projects that are alternatives of or similar to aks-keyvault

vault-sidecar-injector
Kubernetes admission webhook for secure, seamless and dynamic handling of secrets in your applications
Stars: ✭ 55 (+161.9%)
Mutual labels:  k8s, secrets-management
k8s-actions
Enable GitHub developers to deploy to Kubernetes service using GitHub Actions
Stars: ✭ 104 (+395.24%)
Mutual labels:  k8s, aks
ProductsStoreOnKubernetes
Demoing deployment of Docker containers into Kubernetes for both minikube and Azure AKS.
Stars: ✭ 90 (+328.57%)
Mutual labels:  k8s, aks
Fx
A Function as a Service tool makes a function as a container-based service in seconds.
Stars: ✭ 1,679 (+7895.24%)
Mutual labels:  k8s, aks
angular-app-kubernetes
Sample Dockerised angular app deployed on Kubernetes on Azure using AKS
Stars: ✭ 42 (+100%)
Mutual labels:  k8s, aks
beegfs-csi-driver
The BeeGFS Container Storage Interface (CSI) driver provides high performing and scalable storage for workloads running in Kubernetes.
Stars: ✭ 32 (+52.38%)
Mutual labels:  csi-driver
postgres
A PostgreSQL database used by Deis Workflow.
Stars: ✭ 37 (+76.19%)
Mutual labels:  k8s
Az-DevOps-Agent-On-AKS
Build and deploy Azure DevOps Pipeline agent in a container on Azure Kubernetes Service. Elastically scale the DevOps build infrastructure.
Stars: ✭ 26 (+23.81%)
Mutual labels:  aks
iskan
Kubernetes Native, Runtime Container Image Scanning
Stars: ✭ 35 (+66.67%)
Mutual labels:  aks
xx
This tool simplifies the use of common shell, docker, and kubernetes commands
Stars: ✭ 57 (+171.43%)
Mutual labels:  k8s
tondra
Continuous Development on Kubernetes environments with Skaffold
Stars: ✭ 105 (+400%)
Mutual labels:  k8s
ratel-doc
Kubernetes Dashboard 一键式 Kubernetes多集群资源管理平台 k8s 管理平台
Stars: ✭ 153 (+628.57%)
Mutual labels:  k8s
k8s note
k8s学习笔记
Stars: ✭ 27 (+28.57%)
Mutual labels:  k8s
lvm-localpv
CSI Driver for dynamic provisioning of Persistent Local Volumes for Kubernetes using LVM.
Stars: ✭ 86 (+309.52%)
Mutual labels:  csi-driver
Book k8sInfra
< 컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커 >
Stars: ✭ 176 (+738.1%)
Mutual labels:  k8s
k8s-buildkite-plugin
Run any buildkite build step as a Kubernetes Job
Stars: ✭ 37 (+76.19%)
Mutual labels:  k8s
azure
Documentation, tooling and other resources related to the Azure account used by the Jenkins project
Stars: ✭ 20 (-4.76%)
Mutual labels:  aks
dcos-k8s-rust-skaffold-demo
A demo of pipelining Rust application development to Kubernetes on DC/OS with Skaffold.
Stars: ✭ 40 (+90.48%)
Mutual labels:  k8s
k8s-set-context
GitHub Action for setting context and retrieving Kubeconfig before deploying to Kubernetes clusters
Stars: ✭ 51 (+142.86%)
Mutual labels:  k8s
vultr-csi
Container Storage Interface (CSI) Driver for Vultr Block Storage
Stars: ✭ 22 (+4.76%)
Mutual labels:  csi-driver
title titleSuffix description services ms.topic ms.date
Secure secrets with Key Vault
Azure Kubernetes Service
Learn how to get Secrets from Azure Key Vault in Azure Kubernetes Service (AKS) using AAD Pod Identity and Secrets Store CSI provider
container-service
tutorial
05/03/2020

Secure secrets with Key Vault

Introduction

A Secret in Kubernetes is meant to save sensitive and secure data like passwords, certificates, and keys. These Secret objects aren't secret or secure! They're encoded using Base64 and saved into etcd. Also, by default, any pod have access to them.

To secure these secrets, one solution could be to encrypt data at rest in Kubernetes as explained in Kubernetes documentation. But this feature (KMS) is not yet supported in AKS. However some work is in progress. Check the AKS Roadmap and the KMS Plugin for Key Vault.

Another solution would be using Azure Key Vault. It can securely encrypt sensitive data like keys, secrets, files, and certificates. Even more than just encryption, they offer powerful features like key rotation, expiration date and access policies.

Now, to access Key Vault, a password is needed. Thus it will be non-securely saved in a Secret object in etcd! We returned back to the first problem. Fortunately in Azure, AKS can connect to Key Vault or SQL Database… using an Identity. This connection could be done using the open-source project Pod Identity. It uses Azure AD to create an Identity and assign the roles and resources.

Now that we have access to Key Vault, we can use its SDK or REST API in the application to retrieve the secrets. The SDK has support for .NET, Java, Python, JS, Ruby, PHP, etc. Or we can retrieve the secrets from a mounted volume. Historically, in Azure, this solution was implemented through Kubernetes Key Vault Flex Volume. Now it's being deprecated. The new solution is Azure Key Vault provider for Secret Store CSI driver. Which is the Azure implementation of Secrets Store CSI driver.

This tutorial will help you to securely retrieve secrets in Key Vault right from the Pod using Secrets Store CSI and AAD Pod Identity.

Setting up the environment

To complete this workshop, we need az, kubectl and helm CLI. Also, we need to create the following resources in Azure: • AKS cluster that uses Service Principal or Managed Identity through the variable $isAKSWithManagedIdentity. • Key Vault with the following secrets: “DatabaseLogin: DbUserName” and “DatabasePassword: MyP@ssword123456”. • Container Registry (ACR). We provision these resources from the Azure Portal or using the following Powershell script:

$suffix = "demo01"
$subscriptionId = (az account show | ConvertFrom-Json).id
$tenantId = (az account show | ConvertFrom-Json).tenantId
$location = "westeurope"
$resourceGroupName = "rg-" + $suffix
$aksName = "aks-" + $suffix
$aksVersion = "1.16.13"
$keyVaultName = "keyvaultaks" + $suffix
$secret1Name = "DatabaseLogin"
$secret2Name = "DatabasePassword"
$secret1Alias = "DATABASE_LOGIN"
$secret2Alias = "DATABASE_PASSWORD" 
$identityName = "identity-aks-kv"
$identitySelector = "azure-kv"
$secretProviderClassName = "secret-provider-kv"
$acrName = "acrforaks" + $suffix
$isAKSWithManagedIdentity = "true"

# echo "Creating Resource Group..."
$resourceGroup = az group create -n $resourceGroupName -l $location | ConvertFrom-Json

# echo "Creating ACR..."
$acr = az acr create --resource-group $resourceGroupName --name $acrName --sku Basic | ConvertFrom-Json
az acr login -n $acrName --expose-token

If ($isAKSWithManagedIdentity -eq "true") {
echo "Creating AKS cluster with Managed Identity..."
$aks = az aks create -n $aksName -g $resourceGroupName --kubernetes-version $aksVersion --node-count 1 --attach-acr $acrName  --enable-managed-identity | ConvertFrom-Json
} Else {
echo "Creating AKS cluster with Service Principal..."
$aks = az aks create -n $aksName -g $resourceGroupName --kubernetes-version $aksVersion --node-count 1 --attach-acr $acrName | ConvertFrom-Json
}
# retrieve the existing or created AKS
$aks = (az aks show -n $aksName -g $resourceGroupName | ConvertFrom-Json)
# echo "Connecting/authenticating to AKS..."
az aks get-credentials -n $aksName -g $resourceGroupName
echo "Creating Key Vault..."
$keyVault = az keyvault create -n $keyVaultName -g $resourceGroupName -l $location --enable-soft-delete true --retention-days 7 | ConvertFrom-Json
# $keyVault = az keyvault show -n $keyVaultName | ConvertFrom-Json # retrieve existing KV
echo "Creating Secrets in Key Vault..."
az keyvault secret set --name $secret1Name --value "DbUserName" --vault-name $keyVaultName
az keyvault secret set --name $secret2Name --value "P@ssword123456" --vault-name $keyVaultName

[!IMPORTANT]

Key Vault, AKS and Identity are in the same resource group here for simplicity. But they can be deployed on different ones.

Installing Secrets Store CSI driver and Key Vault Provider

We’ll start by installing Secrets Store CSI driver using Helm charts into a separate namespace.

helm repo add csi-secrets-store-provider-azure https://raw.githubusercontent.com/Azure/secrets-store-csi-driver-provider-azure/master/charts
"secrets-store-csi-driver-provider-azure" has been added to your repositories
kubectl create ns csi-driver
namespace/csi-driver created
helm install csi-azure csi-secrets-store-provider-azure/csi-secrets-store-provider-azure --namespace csi-driver
NAME: csi-azure
LAST DEPLOYED: Thu Jun 11 11:57:28 2020
NAMESPACE: csi-driver
STATUS: deployed
REVISION: 1
TEST SUITE: None

Let's check the new created pods:

kubectl get pods --namespace=csi-driver
NAME                                               READY   STATUS              RESTARTS   AGE
csi-azure-csi-secrets-store-provider-azure-9mf84   0/1     ContainerCreating   0          3s
csi-azure-secrets-store-csi-driver-rpn7f           0/3     ContainerCreating   0          3s

Using the Azure Key Vault Provider

Now the driver is installed. Let's use the SecretProviderClass to configure the Key Vault instance to connect to the specific keys, secrets, or certificates to retrieve. Note how we are providing the Key Vault name, resource group, subscription Id, tenant Id, and then the name of the secrets.

$secretProviderKV = @"
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
  name: $($secretProviderClassName)
spec:
  provider: azure
  parameters:
    usePodIdentity: "true"
    useVMManagedIdentity: "false"
    userAssignedIdentityID: ""
    keyvaultName: $keyVaultName
    cloudName: AzurePublicCloud
    objects:  |
      array:
        - |
          objectName: $secret1Name
          objectAlias: $secret1Alias
          objectType: secret
          objectVersion: ""
        - |
          objectName: $secret2Name
          objectAlias: $secret2Alias
          objectType: secret
          objectVersion: ""
    resourceGroup: $resourceGroupName
    subscriptionId: $subscriptionId
    tenantId: $tenantId
"@
$secretProviderKV | kubectl create -f -
secretproviderclass.secrets-store.csi.x-k8s.io/secret-provider-kv created

[!NOTE] Note: This sample used only Secrets in Key Vault, but we can also retrieve Keys and Certificates.

Creating role assignments for AKS cluster (only for Managed Identity)

If we are using AKS with Managed Identity, then we should create the following two role assignments:

# Run the following 2 commands only if using AKS with Managed Identity
If ($isAKSWithManagedIdentity -eq "true") {
az role assignment create --role "Managed Identity Operator" --assignee $aks.identityProfile.kubeletidentity.clientId --scope /subscriptions/$subscriptionId/resourcegroups/$($aks.nodeResourceGroup)
az role assignment create --role "Virtual Machine Contributor" --assignee $aks.identityProfile.kubeletidentity.clientId --scope /subscriptions/$subscriptionId/resourcegroups/$($aks.nodeResourceGroup)
# If user-assigned identities that are not within the cluster resource group
# az role assignment create --role "Managed Identity Operator" --assignee $aks.identityProfile.kubeletidentity.clientId --scope /subscriptions/$subscriptionId/resourcegroups/$resourceGroupName
}

Installing Pod Identity and providing access to Key Vault

The Azure Key Vault Provider offers four modes for accessing a Key Vault instance: Service Principal, Pod Identity, VMSS User Assigned Managed Identity and VMSS System Assigned Managed Identity. Here we'll be using Pod Identity. Azure AD Pod Identity will be used to create an Identity in AAD and assign the right roles and resources. Let's first install it into the cluster.

Installing AAD Pod Identity into AKS

We deploy Pod Identity using a Helm chart. The chart will install Node Managed Identity (NMI) and Managed Identity Controllers (MIC) on each node.

helm repo add aad-pod-identity https://raw.githubusercontent.com/Azure/aad-pod-identity/master/charts
helm install pod-identity aad-pod-identity/aad-pod-identity
kubectl get pods

NAME                                   READY   STATUS              RESTARTS   AGE
aad-pod-identity-mic-c558d8649-4vmj2   1/1     Running             0          29s
aad-pod-identity-mic-c558d8649-rrhvd   1/1     Running             0          29s
aad-pod-identity-nmi-t62zh             1/1     Running             0          29s

Creating or retrieving Azure Identity

If we are using an AKS cluster with Managed Identity, then Azure has already created the Identity resource with AKS. So, we’ll go to retrieve it. But if we created an AKS cluster with Service Principal, then we need to create a new Identity.

# If using AKS with Managed Identity, retrieve the existing Identity
If ($isAKSWithManagedIdentity -eq "true") {
echo "Retrieving the existing Azure Identity..."
$existingIdentity = az resource list -g $aks.nodeResourceGroup --query "[?contains(type, 'Microsoft.ManagedIdentity/userAssignedIdentities')]"  | ConvertFrom-Json
$identity = az identity show -n $existingIdentity.name -g $existingIdentity.resourceGroup | ConvertFrom-Json
} Else {
# If using AKS with Service Principal, create new Identity
echo "Creating an Azure Identity..."
$identity = az identity create -g $resourceGroupName -n $identityName | ConvertFrom-Json
}
 
$identity
{
  "clientId": "a0c038fd-3df3-4eaf-bb34-abdd4f78a0db",
  "clientSecretUrl": "https://control-westeurope.identity.azure.net/subscriptions/<AZURE_SUBSCRIPTION_ID>/resourcegroups/rg-demo/providers/Microsoft.ManagedIdentity/userAssignedIdentities/identity-aks-kv/crede
ntials?tid=<AZURE_TENANT_ID>&oid=f8bb59bd-b704-4274-8391-3b0791d7a02c&aid=a0c038fd-3df3-4eaf
  "id": "/subscriptions/<AZURE_SUBSCRIPTION_ID>/resourcegroups/rg-demo/providers/Microsoft.Managed
Identity/userAssignedIdentities/identity-aks-kv",
  "location": "westeurope",
  "name": "identity-aks-kv",
  "principalId": "000000-b704-4274-8391-3b0791d7a02c",
  "resourceGroup": "rg-demo",
  "tags": {},
  "tenantId": "<AZURE_TENANT_ID>",
  "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
}

Assigning Reader Role to new Identity for Key Vault

The Identity we created earlier will be used by AKS Pods to read secrets from Key Vault. Thus, it should have permissions to do so. We will assign it the Reader role to the KV scope.

az role assignment create --role "Reader" --assignee $identity.principalId --scope $keyVault.id

{
  "canDelegate": null,
  "id": "/subscriptions/<AZURE_SUBSCRIPTION_ID>/resourcegroups/rg-demo/providers/Microsoft.KeyVault/vaults/
az-key-vault-demo/providers/Microsoft.Authorization/roleAssignments/d6bd00b8-9734-4c53-9de3-5a5b203c3286",
  "name": "d6bd00b8-9734-4c53-9de3-5a5b203c3286",
  "principalId": "f8bb59bd-b704-4274-8391-3b0791d7a02c",
  "principalName": "a0c038fd-3df3-4eaf-bb34-abdd4f78a0db",
  "principalType": "ServicePrincipal",
  "resourceGroup": "rg-demo",
  "roleDefinitionId": "/subscriptions/<AZURE_SUBSCRIPTION_ID>/providers/Microsoft.Authorization/roleDefinit
ions/acdd72a7-3385-48ef-bd42-f606fba81ae7",
  "roleDefinitionName": "Reader",
  "scope": "/subscriptions/<AZURE_SUBSCRIPTION_ID>/resourcegroups/rg-demo/providers/Microsoft.KeyVault/vaul
ts/az-key-vault-demo",
  "type": "Microsoft.Authorization/roleAssignments"
}

Providing required permissions for MIC

In case you chose AKS with Service Principal, you need also to grant permissions to the AKS cluster with role “Managed Identity Operator”. For that we will need the Service Principal (SPN) used with AKS.

# Run the following command only if using AKS with Service Principal
If ($isAKSWithManagedIdentity -eq "false") {
echo "Providing required permissions for MIC..."
az role assignment create --role "Managed Identity Operator" --assignee $aks.servicePrincipalProfile.clientId --scope $identity.id
}

{
  "canDelegate": null,
  "id": "/subscriptions/<AZURE_SUBSCRIPTION_ID>/resourcegroups/rg-demo/providers/Microsoft.ManagedIdentity/
userAssignedIdentities/identity-aks-kv/providers/Microsoft.Authorization/roleAssignments/c018c932-c06b-446c-863e-bc85c68
7cf69",
  "name": "c018c932-c06b-446c-863e-bc85c687cf69",
  "principalId": "2736b5eb-e79e-48fa-9348-19f9c64ce7b3",
  "principalName": "http://aks-demoSP-20200430052736",
  "principalType": "ServicePrincipal",
  "resourceGroup": "rg-demo",
  "roleDefinitionId": "/subscriptions/<AZURE_SUBSCRIPTION_ID>/providers/Microsoft.Authorization/roleDefinit
ions/f1a07417-d97a-45cb-824c-7a7467783830",
  "roleDefinitionName": "Managed Identity Operator",
  "scope": "/subscriptions/<AZURE_SUBSCRIPTION_ID>/resourcegroups/rg-demo/providers/Microsoft.ManagedIdenti
ty/userAssignedIdentities/identity-aks-kv",
  "type": "Microsoft.Authorization/roleAssignments"
}

Setting policy to access secrets in Key Vault

We should tell Key Vault to allow the Identity to do only specific actions on the secrets like get, list, delete, update. In our case, we need only permissions for GET. This permission is granted by using a Policy.

az keyvault set-policy -n $keyVaultName --secret-permissions get --spn $identity.clientId

{
  "id": "/subscriptions/<AZURE_SUBSCRIPTION_ID>/resourceGroups/demo-rg/providers/Microsoft.KeyVault/vaults/kv-aks-demo",
  "location": "westeurope",
  "name": "kv-aks-demo",
  "properties": {
    "accessPolicies": [
      {
… code removed for brievety …
        "permissions": {
          "certificates": null,
          "keys": null,
          "secrets": [
            "get"

    "softDeleteRetentionInDays": null,
    "tenantId": "<AZURE_TENANT_ID>",
    "vaultUri": "https://kv-aks-demo.vault.azure.net/"
  },
  "resourceGroup": "demo-rg",
  "tags": {},
  "type": "Microsoft.KeyVault/vaults"
}

[!NOTE] Note: To set policy to access keys or certs in keyvault, replace: --secret-permissions by: --key-permissions or --certificate-permissions.

Adding AzureIdentity and AzureIdentityBinding

The Pod needs to use the Identity to access to Key Vault. We’ll point to that Identity in AKS using AzureIdentity object and then we’ll assign it to the Pod through AzureIdentityBinding.

$aadPodIdentityAndBinding = @"
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentity
metadata:
  name: $($identityName)
spec:
  type: 0
  resourceID: $($identity.id)
  clientID: $($identity.clientId)
---
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentityBinding
metadata:
  name: $($identityName)-binding
spec:
  azureIdentity: $($identityName)
  selector: $($identitySelector)
"@

$aadPodIdentityAndBinding | kubectl apply -f -

azureidentity.aadpodidentity.k8s.io/identity-aks-kv created
azureidentitybinding.aadpodidentity.k8s.io/identity-aks-kv-binding created

[!TIP] Note: Set type: 0 for Managed Service Identity; type: 1 for Service Principal. In this case, we are using managed service identity, type: 0.

[!NOTE] Note the selector here as we’ll reuse it later with the pod that needs access to the Identity.

Accessing Key Vault secrets from a Pod in AKS

At this stage, we can create a Pod and mount CSI driver on which we’ll find the login and password retrieved from Key Vault. Let's deploying a Nginx Pod for testing

$nginxPod = @"
kind: Pod
apiVersion: v1
metadata:
  name: nginx-secrets-store
  labels:
    aadpodidbinding: $($identitySelector)
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
      - name: secrets-store-inline
        mountPath: "/mnt/secrets-store"
        readOnly: true
  volumes:
    - name: secrets-store-inline
      csi:
        driver: secrets-store.csi.k8s.io
        readOnly: true
        volumeAttributes:
          secretProviderClass: $($secretProviderClassName)
"@

$nginxPod | kubectl apply -f -
pod/nginx-secrets-store created

Validating the pod has access to the secrets from Key Vault

Now, we’ll validate all what we have done before. Let’s list and read the content of the mounted CSI volume. If all is fine, we should see the secret values from our Key Vault.

kubectl exec -it nginx-secrets-store ls /mnt/secrets-store/
DATABASE_LOGIN  DATABASE_PASSWORD
kubectl exec -it nginx-secrets-store cat /mnt/secrets-store/DATABASE_LOGIN
DbUserName
kubectl exec -it nginx-secrets-store cat /mnt/secrets-store/DATABASE_PASSWORD
MyP@ssword123456

Clean up resources

To clean up the resources, you will purge Key Vault and delete the created resource groups.

az keyvault purge -n $keyVaultName
az group delete --no-wait --yes -n $resourceGroupName
az group delete --no-wait --yes -n $aks.nodeResourceGroup
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].