deploy-to-aks — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited deploy-to-aks (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are driving a full repository → running pod on AKS iteration loop. This skill orchestrates other skills — read each one before you run its step, pass results forward, and don't duplicate their logic here.
Collect (ask the user once if any are missing):
registry (required) — ACR login server, e.g. myregistry.azurecr.ioresourceGroup (required) — Azure RG containing the AKS clusterclusterName (required) — AKS cluster namenamespace (optional) — defaults to a unique name like staging-<short-hash>imageName (optional) — defaults to the repo directory namerepoPath — the current working directory (confirm with user)targetPlatform — fixed linux/amd64 (standard AKS node arch)environment — fixed productionAfter collection, echo back the resolved values in one block and ask the user to confirm before running Step 1.
Run the steps strictly in order. Retry each step up to 2 times before halting. Keep the user informed after every step.
az account show --query "{tenantId:tenantId, tenantDisplayName:tenantDisplayName, user:user.name}" -o json → current tenant.az account tenant list --query "[].{tenantId:tenantId, displayName:displayName, defaultDomain:defaultDomain}" -o json (fall back to az account list ... | dedupe by tenantId if unavailable).vscode_askQuestions if available.az login --tenant "<selectedTenantId>" and re-check.az account show --query tenantId -o tsv == <selectedTenantId>.tenantId. Confirm: "Using tenant <displayName> (<tenantId>)."az account show --query "{id:id, name:name, tenantId:tenantId}" -o json.az account list --query "[?state=='Enabled' && tenantId=='<tenantId>'].{id:id, name:name}" -o json.az account show --subscription "<id>" ... — tenantId must match Step 1.az account set --subscription "<id>". Confirm: "Using subscription <name> (<id>)."az aks list -g <resourceGroup> --query "[].{name:name, sku:sku.name, fqdn:fqdn}" -o json.clusterName from input or first listed; additional = other clusters in RG; free-text fallback).az aks show -g <resourceGroup> -n "<clusterName>" --query "{name:name, fqdn:fqdn, sku:sku.name, azureRbac:aadProfile.enableAzureRbac, localAccountsDisabled:disableLocalAccounts}" -o json.isAutomatic = sku == "Automatic"isAzureRbac = azureRbac == truelocalAccountsDisabled = localAccountsDisabled == trueaz account show -o json → subscriptionId, userName, userType.userType == "user": az ad signed-in-user show --query id -o tsv → callerPrincipalId.userType == "servicePrincipal": az ad sp show --id <userName> --query id -o tsv → callerPrincipalId.userName as callerPrincipalId.kubectl here. RBAC + kubeconfig fetch happen in Step 11.az acr list --query "[].{name:name, loginServer:loginServer}" -o json.registry matched by loginServer, or first ACR; free-text fallback).<acrName> and <loginServer>.az acr show --name "<acrName>" --query "{name:name, loginServer:loginServer}" -o json.az aks check-acr -g <resourceGroup> -n <clusterName> --acr <loginServer>.az aks update -g <resourceGroup> -n <clusterName> --attach-acr <acrName>.AuthorizationFailed), tell the user:"The AKS cluster cannot pull from this ACR. Attaching requires Owner or User Access Administrator on the ACR resource. Ask someone with that role to run: az aks update -g <rg> -n <cluster> --attach-acr <acrName>."<acrName>). Cluster pull access verified."Follow the analyze-repo skill against the current working directory.
detectedDatabases, and detectedEnvVars with the user.For each target module where detectedDatabases is non-empty, ask:
Skip if no module has detected databases.
For each target module where detectedEnvVars is non-empty, ask:
secret/database/config classifications are correct.Pass the confirmed detectedEnvVars to the Dockerfile and manifest generation steps.
Skip if no module has detected env vars.
For each target module:
generate-dockerfile skill with the analysis context, environment production, and platform linux/amd64.fix-dockerfile skill against it; it writes the remediated file back to disk.Retry up to 2 times if generation/remediation fails.
path = repo (or module) pathimageName = <imageName>:dev (or an immutable tag like <imageName>:git-<shortSha>)platform = linux/amd64fix-dockerfile skill against the current Dockerfile, then retry.fix-dockerfile skill using the scan results as context, then rebuild (Step 9) and rescan. Retry the fix/rebuild/scan loop up to 2 times.Skip this step entirely if isAutomatic !== true AND isAzureRbac !== true.
Otherwise:
clusterScope = /subscriptions/<subscriptionId>/resourceGroups/<resourceGroup>/providers/Microsoft.ContainerService/managedClusters/<clusterName>namespaceScope = <clusterScope>/namespaces/<namespace>az aks get-credentials -g <resourceGroup> -n "<clusterName>" --overwrite-existing (omit --admin; AKS Automatic disables local accounts).canSelfRemediate probe below, emit the remediation block (Case A or B) for missing role Azure Kubernetes Service Cluster User Role @ <clusterScope>, wait for the user, then poll az aks get-credentials every 15 s for up to 5 min.az rest --method post --url "https://management.azure.com<clusterScope>/providers/Microsoft.Authorization/permissions?api-version=2022-04-01" — inspect actions / notActions for Microsoft.Authorization/roleAssignments/write.az role assignment list --assignee <callerPrincipalId> --scope <clusterScope> --include-inherited -o json for any of Owner, User Access Administrator, Role Based Access Control Administrator. If that also fails with AuthorizationFailed, set canSelfRemediate = false.kubectl auth can-i create namespaces (cluster-scoped)kubectl auth can-i create deployments -n <namespace>kubectl auth can-i create services -n <namespace>kubectl auth can-i create configmaps -n <namespace>kubectl auth can-i get pods -n <namespace>create namespaces == no but all namespace-scoped probes pass, surface this and continue only if an admin will pre-create the namespace.no: halt, emit the remediation block for missing roles:Azure Kubernetes Service RBAC Writer @ <namespaceScope> (for deploy/services/configmaps)Azure Kubernetes Service RBAC Admin @ <clusterScope> (additionally, if namespace must be created)kubectl auth can-i checks every 10 s for up to 2 min.fqdn from Step 3 to the hostname in kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'. Run kubectl get nodes --no-headers. Check kubectl get namespace <namespace> --no-headers --ignore-not-found and record namespaceExists.<userName> on cluster <clusterName>. Proceeding."Remediation block format (use for any HALT in Steps 2 and 4):
⚠️ summary, the missing role(s), and one az role assignment create --role "<Role>" --assignee <callerPrincipalId> --scope "<scope>" command per role. Offer to run it (with confirmation), then poll.az role assignment create commands. Include hand-off identifiers (callerPrincipalId, userType, clusterScope, namespaceScope). Do NOT attempt the role assignment yourself.--admin kubeconfig is unavailable." when localAccountsDisabled or isAutomatic is true.clusterType: "generic" (assumes the existing AKS cluster)namespace: <namespace>targetPlatform: "linux/amd64"az aks get-credentials --resource-group <resourceGroup> --name <clusterName> first.<loginServer>/<imageName>:<tag>.<loginServer>.az acr login --name <acrName> and retry.If no manifests exist for the target module(s), follow the generate-k8s-manifests skill.
modulePath = target module pathnamespace = <namespace>environment = productionimage = <loginServer>/<imageName>:<tag>detectedDatabases and detectedEnvVars from Step 5analysis = the analyze-repo result<modulePath>/k8s/.AKS Automatic hardening — if isAutomatic === true, before applying, verify the generated manifests contain:
securityContext.runAsNonRoot: true and securityContext.seccompProfile.type: RuntimeDefault.securityContext.allowPrivilegeEscalation: false and capabilities.drop: ["ALL"].requests and limits on every container (e.g. cpu: 500m / 1000m, memory: 512Mi / 1Gi).The generate-k8s-manifests skill already produces these for environment == production; only add what is missing.
kubectl create namespace <namespace> --dry-run=client -o yaml | kubectl apply -f -.kubectl apply -f <modulePath>/k8s/ --namespace <namespace>.<namespace> to check pod status, readiness, and events.Service of type LoadBalancer or an Ingress is configured, report the external IP / hostname to the user.| Step | Component | Kind |
|---|---|---|
| 5 | analyze-repo | skill |
| 8 (gen) | generate-dockerfile | skill |
| 8 (fix), 9 (on-fail), 10 (on-vuln) | fix-dockerfile | skill |
| 9 | build-image-context | tool |
| 10 | scan-image | tool |
| 12 | prepare-cluster | tool |
| 13 | tag-image | tool |
| 14 | push-image | tool |
| 15 | generate-k8s-manifests | skill |
| 17 | verify-deploy | tool |
✅ Step N — <heading>).linux/amd64 for all builds (standard AKS node arch).az acr login before retrying push.az aks command invoke as an RBAC bypass when isAzureRbac == true — it authenticates as the caller and hits the same Forbidden.--admin kubeconfig when localAccountsDisabled == true — AKS will reject it.vscode_askQuestions for pickers, always include a free-text input so the user can type a value manually.After Step 17 passes, summarize:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.