visit
Azure Active Directory pod-managed identities uses Kubernetes primitives to associate managed identities for Azure resources and identities in Azure Active Directory (AAD) with pods.
The following diagram shows the architecture of the above steps:
Before going any further, we will need to register EnablePodIdentityPreview and install
aks-preview
Azure CLI extension.az feature register --name EnablePodIdentityPreview --namespace Microsoft.ContainerService
az extension update --name aks-preview
export RESOURCE_GROUP=demo-k8s-rg
export CLUSTER_NAME=my-k8s-cluster
az group create --name=${RESOURCE_GROUP} --location eastus
az aks create -g ${RESOURCE_GROUP} -n ${CLUSTER_NAME} --enable-managed-identity --enable-pod-identity --network-plugin azure --enable-addons monitoring --node-count 1 --generate-ssh-keys
export IDENTITY_RESOURCE_GROUP="my-identity-rg"
export IDENTITY_NAME="sp-application-identity"
az group create --name ${IDENTITY_RESOURCE_GROUP} --location eastus
az identity create --resource-group ${IDENTITY_RESOURCE_GROUP} --name ${IDENTITY_NAME}
Then, assign required permissions for the created identity. The identity must have Reader permission in the resource group that contains the virtual machine scale set of our AKS cluster and
acrpull
permission in the resource group to access repositories to pull images from ACR.export IDENTITY_CLIENT_ID="$(az identity show -g ${IDENTITY_RESOURCE_GROUP} -n ${IDENTITY_NAME} --query clientId -otsv)"
export IDENTITY_RESOURCE_ID="$(az identity show -g ${IDENTITY_RESOURCE_GROUP} -n ${IDENTITY_NAME} --query id -otsv)"
export RG_RESOURCE_ID="$(az group show -g ${RESOURCE_GROUP} --query id -otsv)"
export NODE_GROUP=$(az aks show -g ${RESOURCE_GROUP} -n ${CLUSTER_NAME} --query nodeResourceGroup -o tsv)
export NODES_RESOURCE_ID=$(az group show -n $NODE_GROUP -o tsv --query "id")
az role assignment create --role "Reader" --assignee "$IDENTITY_CLIENT_ID" --scope $NODES_RESOURCE_ID
az role assignment create --role "acrpull" --assignee "$IDENTITY_CLIENT_ID" --scope $RG_RESOURCE_ID
az aks pod-identity add --resource-group ${RESOURCE_GROUP} --cluster-name ${CLUSTER_NAME} --namespace dev-ns --name my-sp-pod-identity --identity-resource-id ${IDENTITY_RESOURCE_ID}
export DB_SERVER=my-sp-db-server
export DB_RG=my-db-rg
export DB_NAME=my-sp-db
export PGSSLMODE=require
az group create --name=my-database-rg --location eastus
az postgres server create --resource-group ${DB_RG} --name ${DB_SERVER} --location eastus --admin-user myadmin --admin-password P@ssword123 --sku-name B_Gen5_1
az postgres db create -g ${DB_RG} -s ${DB_SERVER} -n ${DB_NAME}
az postgres server firewall-rule create --resource-group ${DB_RG} --server ${DB_SERVER} -name "AllowAllLinuxAzureIps" --start-ip-address YOUR_LOCAL_CLIENT_IP --end-ip-address YOUR_LOCAL_CLIENT_IP
SET aad_validate_oids_in_tenant = off;
CREATE ROLE myuser WITH LOGIN PASSWORD '<YOU_IDENTITY_CLIENT_ID>' IN ROLE azure_ad_user;
CREATE DATABASE my-sp-db;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO myuser;
Replace <YOUR_IDENTITY_CLIENT_ID> with your identity client id that we created in section 1.
mvn install dependency:copy-dependencies -DskipTests && cd target/dependency; jar -xf ../*.jar && cd ../..
az acr create --resource-group ${RESOURCE_GROUP} --location eastus --name myspdemo --sku Basic
az acr login --name myspdemo && mvn compile jib:build
//169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fossrdbms-aad.database.windows.net&client_id=<YOUR_IDENTITY_CLIENT_ID>
Then, configure a DataSource programmatically in Spring Boot. The configuration script would look similar to this:package com.example.awesomeprject;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.json.JSONTokener;
import org.json.JSONObject;
import java.net.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.apache.log4j.Logger;
@Configuration
public class DataSourceConfig {
public static Logger logger = Logger.getLogger("global");
@Value("${db.host}")
private String Host;
@Value("${db.user}")
private String User;
@Value("${db.name}")
private String Database;
@Value("${client_id}")
private String ClientId;
@Bean
@RefreshScope
public DataSource getDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
try {
URL url = new URL("//169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fossrdbms-aad.database.windows.net&client_id=" + ClientId);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Metadata", "true");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
JSONTokener tokener = new JSONTokener(in);
JSONObject json = new JSONObject(tokener);
String accessToken = json.getString("access_token");
logger.info("accessToken: " + accessToken);
dataSourceBuilder.url(this.Host);
dataSourceBuilder.username(this.User);
dataSourceBuilder.password(accessToken);
in.close();
con.disconnect();
} catch(Exception e) {
e.printStackTrace();
}
return dataSourceBuilder.build();
}
}
Kustomize is a tool included with kubectl 1.14 that “lets you customize raw, template-free YAML files for multiple purposes, leaving the original YAML untouched and usable as is.”
Make a
.k8s/base
directory for all the default configuration templates:apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- service.yaml
- deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deployment
labels:
app: demo
spec:
selector:
matchLabels:
app: demo
strategy:
type: Recreate
template:
metadata:
labels:
app: demo
aadpodidbinding: my-sp-pod-identity
spec:
containers:
- image: myspdemo2021.azurecr.io/awesomeprject:latest
name: demo
ports:
- containerPort: 8080
env:
- name: DB_SCHEMA
valueFrom:
configMapKeyRef:
name: sp-config
key: DB_SCHEMA
- name: DB_DATA
valueFrom:
configMapKeyRef:
name: sp-config
key: DB_DATA
- name: DS_INIT_MODE
valueFrom:
configMapKeyRef:
name: sp-config
key: DS_INIT_MODE
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: sp-config
key: DB_HOST
- name: DB_USER
valueFrom:
configMapKeyRef:
name: sp-config
key: DB_USER
- name: DB_NAME
valueFrom:
configMapKeyRef:
name: sp-config
key: DB_NAME
- name: CLIENT_ID
valueFrom:
secretKeyRef:
name: sp-secret
key: CLIENT_ID
volumeMounts:
- name: config
mountPath: 'app/resources/config'
readOnly: true
volumes:
- name: config
configMap:
name: sp-config
items:
- key: 'schema.sql'
path: 'schema.sql'
- key: 'data.sql'
path: 'data.sql'
apiVersion: v1
kind: Namespace
metadata:
name: ns
apiVersion: v1
kind: Service
metadata:
name: demo-service
labels:
app: demo
spec:
ports:
- protocol: TCP
port: 80
targetPort: 8080
selector:
app: demo
type: LoadBalancer
Then, make .k8s/dev for development environment configuration, Kustomize called this an overlay. Add new configMap.yml, configmap.yml, and kustomization.yaml files into the overlay directory
.k8s/dev
.apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namePrefix: dev-
namespace: dev-ns
commonLabels:
variant: dev
# patchesStrategicMerge:
resources:
- configmap.yaml
- secret.yaml
bases:
- ../base
apiVersion: v1
kind: ConfigMap
metadata:
name: sp-config
data:
DS_INIT_MODE: always
DB_USER: myuser@my-sp-db-server
DB_HOST: jdbc:postgresql://my-sp-db-server.postgres.database.azure.com:5432/my-sp-db?sslmode=require
DB_NAME: my-sp-db
DB_SCHEMA: config/schema.sql
DB_DATA: config/data.sql
data.sql: |
INSERT INTO "user" (firstName, lastName) SELECT 'William','Ferguson'
WHERE
NOT EXISTS (
SELECT id FROM "user" WHERE firstName = 'William' AND lastName = 'Ferguson'
);
schema.sql: |
DROP TABLE IF EXISTS "user";
CREATE TABLE "user"
(
id SERIAL PRIMARY KEY,
firstName VARCHAR(100) NOT NULL,
lastName VARCHAR(100) NOT NULL
);
apiVersion: v1
kind: Secret
data:
CLIENT_ID: CLIENT_ID_ENCODED_WITH_BASE64
metadata:
name: sp-secret
type: Opaque
kustomize build .k8s/dev/. | kubectl apply -f -
Once the application has been deployed, use
kubectl
to check the status of our application pod:kubectl get pods -n dev-ns
NAME READY STATUS RESTARTS AGE
dev-demo-deployment-6499974b5-2srzz 1/1 Running 0 23h
Container insights includes the Live Data feature, which is an advanced diagnostic feature allowing you direct access to your Azure Kubernetes Service (AKS) container logs (stdout/stderror), events, and pod metrics. It exposes direct access to kubectl logs -c, kubectl get events, and kubectl top pods.For more details about Container Insight, refer to this .
Read behind a paywall at