Implementace akv2k8s v Azure Kubernetes Services (AKS)

 

Tento LAB popisuje implementaci projektu akv2k8s v Azure Kuberenetes Services / AKS. LAB používá imperativní způsob deploymentu (Azure CLI příkazy v našem případě). Ve svých prostředích pravděpodobně použijete declarativní způsob deploymentu instancí služeb, tzn. definování infrastruktury jako kód (Infrastructure As A Code) prostřednictvím Azure Resource Manager (ARM), Bicep, nebo Terraform.

Dále budete nejspíše orchestrovat takové declarativní definice ve svých Continuous Integration/Continuous Deployment pipelines (S použitím Azure DevOps, nebo Githubu, či jiného CI/CD nástroje). Infrastruktura popsaná níže neobsahuje jiné bezpečnostně orientovaná témata, která by měla být brána v úvahu a implementována s ohledem na základní bezpečnostní úroveň cloud poskytovatele a bezpečnostní úrovně dle požadavků ve vašem projektu (to může být např.: private endpoints, private cluster deployment, encryption at rest, pokročilejší integrace na AAD atp.). Taktéž byste vždy při používání open source projektů jako je akv2k8s měli navštívit github stránky projektu a popřemýšlet o všech aspektech použití vámi vybraného OpenSource projektu před tím, než ho využijete.

Cíl projektu

Cílem tohoto projektu je:

  • test akv2k8s projektu implementací do Azure Kubernetes Services
  • test funkcionality replikace tzv "secrets" mezi instancemi služeb Azure KeyVault and Azure Kubernetes Services (synchronizace secrets do kubernetes secrets, které jsou trvale uložené v etcd databázi)
  • test funkcionality ve smyslu mapování synchronizovaných secrets jako proměnných do podu, ve kterém běží aplikační kontejner
  • deployment infastruktury dle tohoto designu:

image

Co není součástí projektu

  • deklarativní způsob deploymentu (který by měl být použit společně s DevOps principy, jako součást Cloud Native architektury), v tomto projektu provádíme deployment deklarativním způsobem pouze u částí deploymentu do kubernetes
  • využítí Using Continuous Integration/ Continuous Deployment (CI/CD) pipelines (taktéž jako best practice pro Cloud Native architekturu)
  • mapování secrets projektem akv2k8s do aplikačního kontejneru napřímo (s použitím sidecar kontejneru) bez synchronizace do kubernetes secrets (jedná se o další způsob implementace projektu akv2k8s, pro více informací využijte dokumentaci projektu)

Předpoklady

Pro realizaci projektu je nezbytné:

  • mít přístup k Azure subscribci (potřebujete mít oprávnění owner, k resource group kterou budeme vytvářet, tj v ideálním případě je mít oprávnění owner už na subscribci ve které budeme resource group vytvářet)
  • Laptop s příkazovou řádkou (Windows with Powershell, Linux, Mac, či cokoliv jiného) nebo využít Azure Cloud shell, jestli potřebujete do svého CLI instalovat Azure CLI, využijte odkaz https://docs.microsoft.com/en-us/cli/azure/install-azure-cli
  • Azure CLI musí být ve verzi minimálně "2.31.0", použijte "az upgrade" příkaz pro povýšení Azure CLI na nejnovější verzi, zároveň je nutné mít nainstalované rozšíření Azure CLI "aks-preview" v minimální verzi "0.5.49"

Níže v LABu použijeme variantu Azure CLI.

Celý LAB si můžete zároveň projít v repository GitHubu

Přípravné práce - deployment Azure infrastruktury do Azure Resource Group

Vytvořte resource group do které budete následně provádět deployment dalších instancí služeb, změňte název resource group v proměnné GROUP_NAME a vámi požadovaný azure region v proměnné LOCATION (pro seznam všech azure regionů využijte dokumentaci: https://azure.microsoft.com/en-us/global-infrastructure/geographies/#overview):

GROUP_NAME=rg-aks-test
LOCATION=northeurope
az group create \
    --location $LOCATION \
    --resource-group $GROUP_NAME
Deployment Azure Container Registry (ACR)

Vytvořte Azure Container Registry (ACR). Název ACR musí být globálně unikátní, proto zaměňte název ACR v proměnné ACR_NAME za vámi vybraný název:

# change the name acraktestaks with your value, it must be globally unique!
ACR_NAME=acraktestaks
az acr create \
    --resource-group $GROUP_NAME \
    --name $ACR_NAME \
    --sku Basic
Deployment User Assigned Managed Identities pro AKS

Vytvořte Azure User Assigned Managed Identity pro AKS cluster, zaměňte hodnotu proměnné UAMI_NAME za vlasntí název:

UAMI_NAME=uami-aks
az identity create \
    --resource-group $GROUP_NAME \
    --name $UAMI_NAME

Vyexportujte ID managed identity do nové proměnné UAMI_ID (bude použita později):

UAMI_ID=$(az identity show \
    --resource-group $GROUP_NAME \
    --query "id" \
    --name $UAMI_NAME \
    -o tsv)

Vytvořte Azure User Assigned Managed Identity pro AKS cluster resp. Kubelet, změňte hodnotu proměnné UAMI_KUBELET_NAME za vlastní název:

UAMI_KUBELET_NAME=uami-aks-kubelet
az identity create \
    --resource-group $GROUP_NAME \
    --name $UAMI_KUBELET_NAME

Vyexportujte ID managed identity Kubeletu do nové proměnné UAMI_KUBELET_ID (bude použita později):

UAMI_KUBELET_ID=$(az identity show \
    --resource-group $GROUP_NAME \
    --query "id" \
    --name $UAMI_KUBELET_NAME \
    -o tsv)
Deployment Azure KeyVault (AKV) s integrací na Azure RBAC

Vytvořte Azure KeyVault instanci, změňte hodnotu proměnné KV_NAME za vlastní název, musí být globálně unikátní:

# change the name kv-testaks with your value, it must be globally unique!
KV_NAME=kv-tstaks
az keyvault create \
    --location $LOCATION \
    --resource-group $GROUP_NAME \
    --enable-rbac-authorization true \
    --name $KV_NAME

Vyexportujte ID KeyVaultu do nové proměnné KV_ID:

KV_ID=$(az keyvault show \
    --resource-group $GROUP_NAME \
    --query "id" \
    --name $KV_NAME \
    -o tsv)

Vyexportujte principalId User Assigned Managed Identity Kubeletu do nové proměnné UAMI_KUBELET_PRINCIPALID (bude použita Kubeletem pro přístup k Azure KeyVaultu, resp. k secrets v něm uloženým):

UAMI_KUBELET_PRINCIPALID=$(az identity show \
    --resource-group $GROUP_NAME \
    --query "principalId" \
    --name $UAMI_KUBELET_NAME \
    -o tsv)

A zároveň přidejte takové identitě přístupové oprávnění právě pro secrets daného Azure KeyVaultu. To provedete tak, že vytvoříte role assignment pro Managed Identitu, kterou AKS cluster používá. K tomu použijte built in roli, která je popsána v dokumentaci "https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#key-vault-secrets-user":

az role assignment create \
    --assignee $UAMI_KUBELET_PRINCIPALID \
    --role "Key Vault Secrets User" \
    --scope $KV_ID

V tuto chvíli bychom také měli přidat AAD RBAC roli Azure Key Vault Secret Officer nějakému člověku/týmu/identitě, kdo bude zodpovědný za životní cyklus secretů v Azure KeyVault. Vytvořme tedy proměnnou, která vyexportuje objectId aktuálně přihlášeného uživatele do nové proměnné USER_NAME_OBJECTID:

USER_NAME_OBJECTID=$(az ad signed-in-user show \
    --query "objectId" \
    -o tsv)

A následně přidáme této proměnné built-in roli Azure Key Vault Secret Officer https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#key-vault-secrets-officer:

az role assignment create \
    --assignee $USER_NAME_OBJECTID \
    --role "Key Vault Secrets Officer" \
    --scope $KV_ID
Deployment další nutné RBAC role

Přidejte další nezbytné oprávnění pro managed identities. Tj přidejte oprávnění pro User Assigned Managed Identity AKS clusteru, tak aby měla roli owner nad User Assigned Managed Identity Kubelet serveru (krok nutný pro úspěšnost následného deploymentu AKS clusteru)

Vyexportujte principalId User Assigned Managed Identity AKS clusteru jako novou proměnnou UAMI_ID_PRINCIPALID:

UAMI_ID_PRINCIPALID=$(az identity show \
    --resource-group $GROUP_NAME \
    --query "principalId" \
    --name $UAMI_NAME \
    -o tsv)

Vytvořte nový role assignment:

az role assignment create \
    --assignee $UAMI_ID_PRINCIPALID \
    --role "Owner" \
    --scope $UAMI_KUBELET_ID
Deployment Azure Kubernetes Services (AKS)

Vytvořte Azure Kubernetes Services (AKS) s použitím níže uvedených parametrů (využíváme dříve exportované proměnné), změňte hodnotu proměnné AKS_NAME za vlastní název, musí být globálně unikátní:

# change the name aks-aktest with your value, it must be globally unique!
AKS_NAME=aks-aktest
az aks create \
    --resource-group $GROUP_NAME \
    --attach-acr $ACR_NAME \
    --enable-managed-identity \
    --assign-identity $UAMI_ID \
    --assign-kubelet-identity $UAMI_KUBELET_ID \
    --node-count 2 \
    --generate-ssh-keys \
    --name $AKS_NAME

V případě, že dostanete chybové hlášky s upozorněním na neznámé argumenty, tak aktualizujte „az cli“ s použitím „az update“ příkazu, viz minimální požadavky v úvodní sekci labu.

Vygenerujte si .kubeconfig soubor abyste měli přístup do AKS clusteru:

# Get cluster credentials
az aks get-credentials \
    --resource-group $GROUP_NAME \
    --name $AKS_NAME

Vyzkoušejte přístup do AKS clusteru s použitím "kubectl" utility:

kubectl get nodes

Měli byste obdržet výstup podobný tomuto:

kolarik@Azure:~$ kubectl get nodes
NAME                                STATUS   ROLES   AGE   VERSION
aks-nodepool1-41796624-vmss000000   Ready    agent   15m   v1.21.7
aks-nodepool1-41796624-vmss000001   Ready    agent   15m   v1.21.7

Deployment akv2k8s controlleru

Deploy kubernetes namespace

Vytvořte kubernetes namespace:

NAMESPACE_NAME=akv2k8s
kubectl create namespace $NAMESPACE_NAME --dry-run=client -o yaml | kubectl apply -f -

Měli byste obdržet výstup podobný tomuto:

namespace/akv2k8s created
Deploy akv2k8s controlleru s použitím helm chartu

Nyní, vytvořte akv2k8s controller s použitím helm chartu do kubernetes namespace. Přidejte "spv-charts" do lokálního repository:

helm repo add spv-charts https://charts.spvapi.no

Měli byste obdržet výstup podobný tomuto:

"spv-charts" has been added to your repositories

Nyní aktualizujte cache lokálního helm repository:

helm repo update

Měli byste obdržet výstup podobný tomuto:

Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "spv-charts" chart repository
Update Complete. ⎈Happy Helming!⎈

Nyní nainstalujte controller s využitím "helm upgrade" a parametrů:

helm upgrade -i \
    akv2k8s \
    spv-charts/akv2k8s \
    --namespace $NAMESPACE_NAME

Měli byste obdržet výstup podobný tomuto:

Release "akv2k8s" does not exist. Installing it now.
W0103 11:43:23.082623     167 warnings.go:67] policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget
W0103 11:43:23.563168     167 warnings.go:67] policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget
NAME: akv2k8s
LAST DEPLOYED: Mon Jan  3 11:43:20 2022
NAMESPACE: akv2k8s
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Congratulations! You've successfully installed Azure Key Vault to Kubernetes.
For more information see the documentation at https://akv2k8s.io.

Jestli jste došli až sem, tak jste úspěšně nainstalovali potřebnou infrastrukturu, včetně AKS clusteru a controlleru akv2k8s dovnitř kubernetes clusteru.

Nyní můžete vidět, že se nám API schéma aktualizovalo o nové API, zkuste pustit následující příkaz:

kubectl -n akv2k8s api-resources

a uvidíte, že je zde nový typ objektu "akvs":

image

Podívejme se co vše nám helm chart vytvořil:

kubectl -n akv2k8s get all

Měli byste obdržet výstup podobný tomuto:

NAME                                       READY   STATUS    RESTARTS   AGE
pod/akv2k8s-controller-d4ff9564c-qc5vk     1/1     Running   0          109m
pod/akv2k8s-envinjector-69f4d6bcb9-2ltcj   1/1     Running   0          109m
pod/akv2k8s-envinjector-69f4d6bcb9-mpp4f   1/1     Running   0          109m

NAME                          TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                   AGE
service/akv2k8s-controller    ClusterIP   10.0.92.173   <none>        9000/TCP                  109m
service/akv2k8s-envinjector   ClusterIP   10.0.80.235   <none>        443/TCP,80/TCP,9443/TCP   109m

NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/akv2k8s-controller    1/1     1            1           109m
deployment.apps/akv2k8s-envinjector   2/2     2            2           109m

NAME                                             DESIRED   CURRENT   READY   AGE
replicaset.apps/akv2k8s-controller-d4ff9564c     1         1         1       109m
replicaset.apps/akv2k8s-envinjector-69f4d6bcb9   2         2         2       109m

Můžete se podívat na logy controlleru nově vytvořeného controlleru akv2k8s, zaměňte ale název podu akv2k8s-controller-d4ff9564c-qc5vk za tu vaši, kterou jste získali ve výstupu z předchozího příkazu:

kubectl -n akv2k8s logs akv2k8s-controller-d4ff9564c-qc5vk

Měli byste obdržet výstup podobný tomuto:

I0104 09:44:44.261444       1 main.go:96] "log settings" format="text" level="2"
I0104 09:44:44.261502       1 version.go:31] "version info" version="1.3.0" commit="a375982" buildDate="2021-08-06T06:52:07Z" component="controller"
W0104 09:44:44.261605       1 client_config.go:615] Neither --kubeconfig nor --master was specified.  Using the inClusterConfig.  This might not work.
I0104 09:44:44.263070       1 main.go:161] "Creating event broadcaster"
I0104 09:44:44.836258       1 controller.go:167] "setting up event handlers"
I0104 09:44:44.836291       1 controller.go:178] "starting azurekeyvaultsecret controller"
I0104 09:44:45.336466       1 controller.go:196] "starting azure key vault secret queue"
I0104 09:44:45.336506       1 controller.go:199] "starting azure key vault deleted secret queue"
I0104 09:44:45.336516       1 controller.go:202] "starting azure key vault queue"
I0104 09:44:45.336525       1 controller.go:205] "started workers"

Pamatujte si, jak se podíváte na logy controlleru, velmi pravděpodobně budete takové logy využívat v případě řešení jakýchkoliv obtíží, uvidíte zde informace ohledně synchronizace secrets, včetně případných potíží !!!

Vytvoření testovacích secrets v Azure KeyVault

Vytvoříte testovací secrets v Azure KeyVaultu, můžete jakkoliv změnit hodnoty proměnných, jen si pak nezapomeňte aktualizovat konfigurační scripty v následujících sekcích, jelikož ty konfigurační scripty nejsou parametrizované a mapují se přímo na tyto hodnoty:

SECRET_NAME1="secretname1"
SECRET_VALUE1="TopSecretPassword"
az keyvault secret set \
    --vault-name $KV_NAME \
    --name $SECRET_NAME1 \
    --value $SECRET_VALUE1

SECRET_SQL="sqlconnectionstring"
SECRET_SQL_VALUE="TopSecretConnectionString"
az keyvault secret set \
    --vault-name $KV_NAME \
    --name $SECRET_SQL \
    --value $SECRET_SQL_VALUE

Měli byste pro každý secret obdržet výstup podobný tomuto:

{
  "attributes": {
    "created": "2022-01-04T09:58:02+00:00",
    "enabled": true,
    "expires": null,
    "notBefore": null,
    "recoveryLevel": "Recoverable+Purgeable",
    "updated": "2022-01-04T09:58:02+00:00"
  },
  "contentType": null,
  "id": "https://kv-tstaks.vault.azure.net/secrets/sqlconnectionstring/80a419159fb94611a91f616295bd33bf",
  "kid": null,
  "managed": null,
  "name": "sqlconnectionstring",
  "tags": {
    "file-encoding": "utf-8"
  },
  "value": "TopSecretConnectionString"
}

Záměrně jsem zde nechal celý výstup, tak abyste viděli celé id secretu, včetně jeho názvu (/sqlconnectionstring/) a jeho verze (/80a419159fb94611a91f616295bd33bf), verze se s každou další změnou mění a akv2k8s controller v kubernetes synchronizuje právě nové verze do kubernetes secrets.

Můžete si zobrazit všechny secrety z keyvaultu:

az keyvault secret list --vault-name $KV_NAME -o table

Měli byste obdržet výstup podobný tomuto:

Name                 Id                                                             ContentType    Enabled    Expires
-------------------  -------------------------------------------------------------  -------------  ---------  ---------
secretname1          https://kv-tstaks.vault.azure.net/secrets/secretname1                         True
sqlconnectionstring  https://kv-tstaks.vault.azure.net/secrets/sqlconnectionstring                 True

nebo si můžete zobrazit seznam secrets v GUI Azure KeyVault instance.

Vytvoření akvs mapovacích objektů uvnitř kubernetes (akvs)

Nejprve vytvořte namespace pro aplikaci, později v tomto namespace vytvoříte secrets, je nutné mít secrets ve stejném namespace jako aplikaci z důvodu budoucích referencí:

NAMESPACE_NAME_APP=app
kubectl create namespace $NAMESPACE_NAME_APP --dry-run=client -o yaml | kubectl apply -f -

Měli byste obdržet výstup podobný tomuto:

namespace/app created

Nyní se podívejte na soubor /manifests/akv.yaml, připravil jsem zde 2 objekty deklarativním způsobem, taktéž si můžete celé repository naklonovat do vašeho lokálního gitu:

DIR_NAME=manifests
mkdir $DIR_NAME
cd $DIR_NAME
vi akv.yaml #and put content of file bellow

Změnte ale hodnoty v yaml souboru, tak aby se popis správně odkazoval na existující odkazy, všímejte si těch položek, za kterými je "#" a zkontrolujte validnost dané hodnoty:

# secrets for Persistent storage
apiVersion: spv.no/v2beta1
kind: AzureKeyVaultSecret
metadata:
  name: akvs-secret-name1 # 1. name of akvs object
  namespace: app
spec:
  vault:
    name: kv-tstaks # 2. name of key vault, change IT with your value!
    object:
      name: secretname1 # 3. name of the akv object
      type: secret # 4. akv object type
  output: 
    secret: 
      name: akv-secret-name1 # 5. kubernetes secret name
      dataKey: secretname1 # 6. key to store object value in kubernetes apiVersion: v1
---
apiVersion: spv.no/v2beta1
kind: AzureKeyVaultSecret # 1. name of akvs object
metadata:
  name: akvs-secret-sql
  namespace: app
spec:
  vault:
    name: kv-tstaks # 2. name of key vault, change IT with your value!
    object:
      name: sqlconnectionstring # 3. name of the akv object
      type: secret # 4. akv object type
  output: 
    secret: 
      name: akv-sql # 5. kubernetes secret name
      dataKey: sqlconnectionstring # 6. key to store object value in kubernetes apiVersion: v1

Následně tento manifest soubor uložte:

image

A následně proveďte deployment manifest souboru do kubernetes clusteru:

kubectl apply -f ~/manifests/akv.yaml

Měli byste obdržet výstup podobný tomuto:

azurekeyvaultsecret.spv.no/akvs-secret-name1 created
azurekeyvaultsecret.spv.no/akvs-secret-sql created

Vypište se seznam objektů akvs (mapovací objekty na kuberentes secrets dle předchozího yaml souboru):

kubectl -n app get akvs

Jestli jste udělali někde chybu, tak pravděpodobně nevidíte objekty v synchronizovaném stavu:

NAME                VAULT        VAULT OBJECT   SECRET NAME   SYNCHED   AGE
akvs-secret-name1   kv-testaks   SECRET-NAME1                           20m
akvs-secret-sql     kv-testaks   SECRET-SQL                             20m

Jestli objekty nejsou v synchronizovaném stavu, tak se běžte podívat na logy akv2k8s controlleru, tak jak jsme si již zkoušeli v předchozích krocích a podívejte se v logu co je chybně (mohou to být přístupové práva, sítě, reference atp.). Jestli jste vše udělali bez chyby, tak byste měli obdržet výstup podobný tomuto:

NAME                VAULT        VAULT OBJECT          SECRET NAME        SYNCHED   AGE
akvs-secret-name1   kv-testaks   secretname1           akv-secret-name1   5s        5m44s
akvs-secret-sql     kv-testaks   sqlconnectionstring   akv-sql            5s        5m44s

Zároveň byste měli zkontrolovat, zda-li bytvořeny nějaké objekty typu kubernetes secrets:

kubectl -n app get secrets

V případě potíží uvidíte pouze default servisní token secret:

NAME                  TYPE                                  DATA   AGE
default-token-4fjp5   kubernetes.io/service-account-token   3      38m

Jestli jsou vaše akvs objekty správně synchronizované, dostanete výstup podobný tomuto:

NAME                  TYPE                                  DATA   AGE
akv-secret-name1      Opaque                                1      96s
akv-sql               Opaque                                1      96s
default-token-4fjp5   kubernetes.io/service-account-token   3      72m

Zkuste si následně popsat nějaký secret a podívat se do něj, zdali něco obsahuje:

kubectl -n app describe secret akv-secret-name1

Měli byste obdržet výstup podobný tomuto:

kolarik@Azure:~$ kubectl -n app describe secret akv-secret-name1
Name:         akv-secret-name1
Namespace:    app
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
secretname1:  17 bytes

Jak asi nejspíše víte, tak kubernetes secrets jsou ukládány do perzistentní vrstvy kubernetes, tj do databáze etcd. Ta není šifrovaná, položky v ní jsou encodované base64 algoritmem, to znamená, že v případě, že v daném namespace máme příslušené oprávnění, můžeme zkusit si daný obsah zobrazit a přes base64 utilitu dekódovat:

kubectl -n app get secrets/akv-secret-name1 --template={ {.data.secretname1} } | base64 -d

Z výstupu bychom měli dostat dekódovaný obsah :)

Že je toho na vás příliš? Dobře dáme si přestávku. Příště začneme vytvořením testovací aplikace a mapováním objektů/secrets

Vítejte zpět. A bez dlouhého zdržování se pustíme rovnou do práce.

Vytvoření testovací aplikace a mapování objektů/secrets

Nyní si zkuste vytvořit jednoduchou testovací aplikaci a namapovat pro ni secrets ve formě proměnných, abychom otestovali celý koncept:

# Go to the manigests folder if you did not so far
cd ~/manifests
kubectl create deployment nginx --image=nginx --dry-run=client --namespace=app -o yaml > nginx.yaml

Přízak použije tzv. dry-run, tj s pomocí výstupu do yaml formátu a přesměrováním do souboru provede vytvoření základního yaml konfiguračního souboru, který definuje deployment typu deployment a použije k tomu image kontejneru nginx z veřejně přístupného registru https://hub.docker.com, který je označen tagem latest, pojmenuje takový deployment "nginx" and vytvoří ho do namespace který se jmenuje "app", kde jsou již synchronizované secrets, které později použijeme.

V případě že se na obsah souboru podáváte:

# Go to the manigests folder if you did not so far
cd ~/manifests
cat nginx.yaml

měli byste vidět obsah podobný tomuto výstupu:

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
  namespace: app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}

Nyní aplikujte manifest soubor do kubernetes clusteru, vytvoříte tím deployment, replicaset a pod:

cd ~/manifests
kubectl apply -f  nginx.yaml

Zkontrolujte co jste vytvořili:

kubectl -n app get deploy,pod,rs,service

měli byste vidět obsah podobný tomuto výstupu:

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           33s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6799fc88d8-cgc6z   1/1     Running   0          33s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-6799fc88d8   1         1         1       33s

Jak vidíte, vytvořili jsme 1 x deployment, 1 x replicaset a 1x deployment.

Nyní zkuste pustit příkaz uvnitř kontejneru, v podu, kde zkusíme vypsat pomocí příkazu printenv všechny proměnné, nezapomeňte zaměnit název podu za ten váš:

# change pod name nginx-6799fc88d8-cgc6z with your real one
kubectl -n app exec nginx-6799fc88d8-cgc6z it -- printenv

měli byste vidět obsah podobný tomuto výstupu:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=nginx-6799fc88d8-cgc6z
NGINX_VERSION=1.21.5
NJS_VERSION=0.7.1
PKG_RELEASE=1~bullseye
KUBERNETES_PORT=tcp://10.0.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.0.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.0.0.1
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
HOME=/root

Pamatujte si tento výstup (zkopírujte si ten obsah někam pro budoucí porovnání) ... zkusíme nyní do proměnných přidat hodnoty z kubernetes secrets což je cíl našeho labu.

Jestli zeditujeme opět yaml manifest soubor a znovu jej zaplikujeme, tak nám vytvoří nový replicaset a nové pody. (v reálném projektu to však za vás dělají agenti které spouští vaše DevOps pipelines)

Zeditujte nyní manifest soubor a přidejte reference na secrets. Pro snazší orientaci jsem položky označil poznámkou s textem "added new line". Zároveň můžete smazat nepotřebné řádky jako jsou timespamps a status:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
  namespace: app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  strategy: {}
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - env: # added new line
        - name: SECRET_NAME1 # added new line
          valueFrom: # added new line
            secretKeyRef: # added new line
              name: akv-secret-name1 # added new line
              key: secretname1 # added new line
        - name: SQL_CONNECTION_STRING # added new line
          valueFrom: # added new line
            secretKeyRef: # added new line
              name: akv-sql # added new line
              key: sqlconnectionstring # added new line
        image: nginx
        name: nginx
        resources: {}

Uložte změny ":wq" ve vimu.

A nyní proveďte znovu aplikaci změn:

cd ~/manifests
kubectl apply -f  nginx.yaml

Jestli neuvidíte nějakou chybovou hlášku, tak byste měli obdržet výstup podobný tomuto:

deployment.apps/nginx configured

Podívejte se, co jste vytvořili:

kubectl -n app get deploy,pod,rs,service

Měli byste obdržet výstup, který ukazuje, že došlo k vytvoření nového replicasetu a podu:

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           41m

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-67cfb48f7c-lwwnj   1/1     Running   0          99s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-55ddf89fb7   0         0         0       18m
replicaset.apps/nginx-6799fc88d8   0         0         0       41m
replicaset.apps/nginx-67cfb48f7c   1         1         1       99s

Nyní konečně zkuste znovu vypsat proměnné zevnitř kontejneru, opět nezapomeňte nahradit název podu v příkazu níže za ten váš:

# change pod name nginx-67cfb48f7c-lwwnj with your real one
kubectl -n app exec nginx-67cfb48f7c-lwwnj it -- printenv

Měli byste obdržet výstup zobrazující taktéž proměnné, které mají stejné hodnoty jak ty v Azure Key Vaults:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=nginx-67cfb48f7c-lwwnj
NGINX_VERSION=1.21.5
NJS_VERSION=0.7.1
PKG_RELEASE=1~bullseye
SQL_CONNECTION_STRING=TopSecretConnectionString
SECRET_NAME1=TopSecretPassword
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.0.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.0.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.0.0.1
KUBERNETES_SERVICE_HOST=10.0.0.1
HOME=/root

image

Jestli jste došli až sem, tak jste vyzkoušeli cíl tohoto projektu, synchronizovali jste Azure KeyVault secrets do kubernetes secrets a namapovali je přes proměnné do aplikace.

Gratuluji Vám !!!

Na konec nezapomeňte smazat všechny vytvořené objekty v LABu, tj smazat celou resource group:

az group delete --resource-group $GROUP_NAME

Tuto implementaci Adam provedl na živé ukázce během webináře "Jak na Hardcoded credentials?", jeho záznam můžete shlédnou po registraci

Sdílej v médiích

implementace-akv2k8s-v-azure-kubernetes-services-aks

Kontakt

Nenašli jste, co hledáte? Pošlete nám zprávu a zůstaneme s vámi ve spojení.

* Vyžadované pole. Osobní data použijeme pouze pro vypracování odpovědi na dotaz. Pravidla zpracování osobních údajů.

* Souhlas se zpracováním údajů

map us
map eu