Production-grade platform engineering handbook — Kubernetes, Terraform, Flux CD, GitHub Actions, AWS, and more.
77
97%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Advisory
Suggest reviewing before use
Structured guidance for Azure identity, resource governance, AKS platform patterns, and production-readiness review.
/platform-skills:azure identity # Workload Identity, OIDC federation, managed identities, Entra ID
/platform-skills:azure tagging # common_tags pattern, Azure Policy enforce/remediate, AKS MC_ group
/platform-skills:azure aks # AKS provisioning, add-ons, Flux/Argo bootstrap, node pools
/platform-skills:azure rbac # role assignment scoping, custom roles, audit over-permissioned identities
/platform-skills:azure review # production-readiness checklist for an Azure environmentWhen invoked with no arguments, ask before proceeding:
Q1 — Mode?
What do you need?
1. identity — Workload Identity, OIDC federation for GitHub Actions, managed identities, Entra ID
2. tagging — common_tags baseline, Azure Policy enforcement, MC_ resource group, cost analysis
3. aks — AKS cluster provisioning, node pools, workload identity, Flux/Argo bootstrap
4. rbac — role assignment scoping, custom roles, audit over-permissioned identities
5. review — production-readiness checklist (tagging, RBAC, OIDC, protected environments)
Enter 1–5 or mode name:Q2 — Context (after mode selected):
What needs Azure access — a GitHub Actions workflow, an in-cluster workload, or a human team?Paste your Terraform module or describe the resource types you need to tag.New cluster or modifying existing? What add-ons are needed (Flux, Argo CD, ESO, Linkerd)?Describe the identity (user, group, managed identity) and what it needs to do.Describe the environment — how many subscriptions, which workloads, any compliance requirements?Triggers: Workload Identity, OIDC, managed identity, service principal, federated credential, GitHub Actions Azure login, Entra ID
Read references/azure.md before responding.
# Create a user-assigned managed identity
az identity create \
--name github-actions-deploy \
--resource-group platform-rg \
--location northeurope
# Get the identity's client ID
CLIENT_ID=$(az identity show \
--name github-actions-deploy \
--resource-group platform-rg \
--query clientId -o tsv)
# Add a federated credential — scoped to a specific repo and branch
az identity federated-credential create \
--name github-main-branch \
--identity-name github-actions-deploy \
--resource-group platform-rg \
--issuer https://token.actions.githubusercontent.com \
--subject repo:org/repo:ref:refs/heads/main \
--audience api://AzureADTokenExchangeGitHub Actions workflow:
permissions:
id-token: write
contents: read
steps:
- uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}# Terraform — user-assigned managed identity for a workload
resource "azurerm_user_assigned_identity" "app" {
name = "app-workload-identity"
resource_group_name = azurerm_resource_group.this.name
location = var.location
}
# Federated credential — links the Kubernetes service account to the managed identity
resource "azurerm_federated_identity_credential" "app" {
name = "app-k8s-sa"
resource_group_name = azurerm_resource_group.this.name
parent_id = azurerm_user_assigned_identity.app.id
audience = ["api://AzureADTokenExchange"]
issuer = azurerm_kubernetes_cluster.this.oidc_issuer_url
subject = "system:serviceaccount:app-team:app-sa"
}Kubernetes service account with workload identity annotation:
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: app-team
annotations:
azure.workload.identity/client-id: "<managed-identity-client-id>"Pod label to opt in:
spec:
template:
metadata:
labels:
azure.workload.identity/use: "true"| Mistake | Fix |
|---|---|
| Using service principal secrets for GitHub Actions | Replace with OIDC federated credential |
Forgetting azure.workload.identity/use: "true" label on pods | Add the label to the pod template spec |
subject in federated credential does not match the SA namespace/name | system:serviceaccount:<namespace>:<sa-name> — must match exactly |
| Identity scoped at subscription level for app workloads | Scope role assignment to the resource group or specific resource |
Triggers: tags, tagging, common_tags, Azure Policy, MC_, cost allocation, chargeback, compliance tags
Read references/azure.md → Tagging resources section before responding.
# variables.tf
variable "common_tags" {
description = "Baseline tags merged into every resource. Keys are defined by the organization."
type = map(string)
}
# locals.tf
locals {
common_tags = var.common_tags
}
# Every resource uses merge — resource-level tags extend the baseline
resource "azurerm_kubernetes_cluster" "this" {
name = var.cluster_name
location = var.location
resource_group_name = azurerm_resource_group.this.name
tags = merge(local.common_tags, {
component = "aks-control-plane"
})
}resource "azurerm_kubernetes_cluster" "this" {
node_resource_group = "mc-${var.cluster_name}-nodes"
tags = merge(local.common_tags, {
component = "aks-control-plane"
})
}
# Tag the MC_ group explicitly — AKS does not inherit tags automatically
resource "azurerm_resource_group_tag" "mc_tags" {
for_each = local.common_tags
resource_group_name = azurerm_kubernetes_cluster.this.node_resource_group
tag_key = each.key
tag_value = each.value
depends_on = [azurerm_kubernetes_cluster.this]
}# Start with audit during rollout, then switch to deny once estate is clean
az policy assignment create \
--name "require-team-tag" \
--display-name "Require team tag on all resources" \
--policy "/providers/Microsoft.Authorization/policyDefinitions/<built-in-id>" \
--scope "/subscriptions/<subscription-id>" \
--enforcement-mode DoNotEnforce # change to Default when ready to enforce
# Remediate existing non-compliant resources
az policy remediation create \
--name "tag-remediation-$(date +%Y%m%d)" \
--policy-assignment <assignment-id> \
--resource-discovery-mode ExistingNonCompliantValidation:
# Check compliance state
az policy state summarize --subscription <subscription-id> \
--filter "policyDefinitionName eq '<policy-id>'"Triggers: AKS, cluster, node pool, provision, bootstrap, Flux on AKS, Argo on AKS, add-ons
Read references/azure.md before responding.
resource "azurerm_kubernetes_cluster" "this" {
name = var.cluster_name
location = var.location
resource_group_name = azurerm_resource_group.this.name
dns_prefix = var.cluster_name
kubernetes_version = var.kubernetes_version
node_resource_group = "mc-${var.cluster_name}-nodes"
# System node pool
default_node_pool {
name = "system"
vm_size = "Standard_D4s_v5"
node_count = 3
os_disk_size_gb = 128
type = "VirtualMachineScaleSets"
zones = ["1", "2", "3"]
only_critical_addons_enabled = true # system pool: control-plane add-ons only
}
# Workload identity + OIDC issuer (required for managed identity federation)
workload_identity_enabled = true
oidc_issuer_enabled = true
# Managed identity for the cluster itself
identity {
type = "SystemAssigned"
}
# Azure CNI Overlay — scales further than kubenet, simpler than full CNI
network_profile {
network_plugin = "azure"
network_plugin_mode = "overlay"
network_policy = "calico"
service_cidr = "10.96.0.0/16"
dns_service_ip = "10.96.0.10"
}
tags = merge(local.common_tags, {
component = "aks-control-plane"
})
}
# User node pool for workloads
resource "azurerm_kubernetes_cluster_node_pool" "workload" {
name = "workload"
kubernetes_cluster_id = azurerm_kubernetes_cluster.this.id
vm_size = "Standard_D8s_v5"
node_count = 3
zones = ["1", "2", "3"]
mode = "User"
tags = merge(local.common_tags, {
component = "aks-workload-nodes"
})
}# Get credentials
az aks get-credentials \
--resource-group <rg> \
--name <cluster> \
--overwrite-existing
# Verify nodes are ready
kubectl get nodes
# Bootstrap Flux (if using GitOps)
flux bootstrap github \
--owner=<org> \
--repository=<gitops-repo> \
--branch=main \
--path=clusters/<cluster-name>For Flux patterns → /platform-skills:gitops
For Argo CD → /platform-skills:gitops
| Pool | Purpose | Node type |
|---|---|---|
system | kube-system, CoreDNS, metrics-server | Small, stable, zonal |
workload | Application pods | Right-sized for workload type |
spot | Batch jobs, non-critical | Spot VMs for cost reduction |
Taint system pool to prevent workload scheduling:
node_taints = ["CriticalAddonsOnly=true:NoSchedule"]Triggers: role assignment, contributor, owner, custom role, over-permissioned, least privilege, audit RBAC
Read references/azure.md → RBAC and identity patterns before responding.
| Identity type | Assignment scope |
|---|---|
| Platform team | Management group or subscription |
| Workload team | Resource group |
| Automation / managed identity | Specific resource or resource group |
| Never | Owner or Contributor to a service principal |
# Assign a built-in role scoped to a resource group
az role assignment create \
--assignee <managed-identity-client-id-or-user-upn> \
--role "Contributor" \
--scope "/subscriptions/<sub>/resourceGroups/<rg>"
# Scoped to a specific resource
az role assignment create \
--assignee <managed-identity-client-id> \
--role "Key Vault Secrets User" \
--scope "/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault-name>"# Find all Owner and Contributor assignments on a subscription
az role assignment list \
--subscription <subscription-id> \
--query "[?roleDefinitionName=='Owner' || roleDefinitionName=='Contributor']" \
-o table
# Find service principals with Owner
az role assignment list \
--subscription <subscription-id> \
--query "[?principalType=='ServicePrincipal' && roleDefinitionName=='Owner']" \
-o table{
"Name": "AKS Metrics Reader",
"Description": "Can read AKS metrics and node pools. Cannot modify.",
"Actions": [
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/agentPools/read",
"Microsoft.Insights/metrics/read"
],
"NotActions": [],
"AssignableScopes": ["/subscriptions/<sub>"]
}az role definition create --role-definition custom-role.jsonTriggers: review, production ready, production checklist, audit my Azure config
Structured production-readiness review. Ask for:
Then evaluate against:
CRITICAL (must fix before production)
❌ Long-lived service principal secrets for automation — replace with managed identity + OIDC
❌ Owner or Contributor assigned to a service principal — violates least privilege
❌ No resource tagging — blocks cost allocation, ownership tracking, and policy compliance
❌ AKS without workload_identity_enabled = true — forces static credentials in pods
❌ No protected environments in GitHub Actions for production subscription appliesWARNING (should fix)
⚠️ Tags missing from MC_ resource group — AKS does not inherit automatically
⚠️ Single subscription for all environments — mix prod and non-prod increases blast radius
⚠️ No Azure Policy enforce tagging — relies on developer discipline
⚠️ ClusterRoleBinding to workload identity — scope to RoleBinding unless cross-namespace access is required
⚠️ System and workload nodes in same pool — system pool should have CriticalAddonsOnly taintINFORMATIONAL
ℹ️ Cost Management tags not validated in CI — add OPA/Conftest gate on terraform plan JSON
ℹ️ No Management Group hierarchy — direct subscription assignment makes policy rollout harder
ℹ️ AKS node pool not zone-redundant — add zones: ["1","2","3"] for HAHandoffs:
/platform-skills:terraform/platform-skills:secrets/platform-skills:gitopsazurerm provider has no default_tags; use merge(local.common_tags, {...}) in every resource and module. The merge pattern is mandatory.azurerm_resource_group_tag or node_resource_group_tags must be added explicitly.azurerm version below 3.87 for node_resource_group_tags — check provider version in versions.tf.Full guidance: references/azure.md
For Terraform module generation: /platform-skills:terraform
For in-cluster secrets (Azure Key Vault via ESO): /platform-skills:secrets
Examples:
examples/azure/ — AKS cluster, workload identity, resource group baseline.claude-plugin
.github
assets
commands
docs
examples
agent-self-improve
argocd
awesome-docs
aws
cloudfront
functions
lambda-edge
functions
azure
compliance
conventional-commits
datadog
llm-observability
demo
documentation
dora
dynatrace
fluxcd
github-actions
composite-actions
configure-cloud
db-migrate
docker-build-push
k8s-deploy
notify-slack
pr-comment
release-tag
security-scan
setup-env
setup-terraform
terraform-plan
helm
web-service
templates
karpenter
kubernetes
kyverno
mcp
observability
openshift
pr-review
ownership
runtime-security
setup-agents
terraform
references
skills
platform-skills
tests
website