AID-M-005.001: Secure Configuration Template Development

Version 1.20261015 · Actionable sub-technique

Cover the design-phase authoring, versioning, review, and static validation of secure configuration templates for AI infrastructure, containers, and development platforms. Authoring validation checks that the complete template set resolves external sources, base images, and dependency locks to immutable approved versions and rejects unresolved placeholders.

Pillars: infra

Lifecycle: scoping

Scope boundary

Owns authoring, versioning, review, and static validation of secure configuration templates, including immutable external sources, digest-pinned base images, dependency locks, and resolved placeholders. It does not deploy, enforce, or score runtime conformance.

AID-M-005.002: AID-M-005.001 creates and statically validates the secure templates; AID-M-005.002 converts approved requirements into signed policy-as-code, measurable posture criteria, and build or release gates. A reviewed template is an input to the gate, not evidence that a release or deployed environment conforms.

Implementation guidance

AID-M-005.001-G001

Author, version, and statically validate secure Infrastructure-as-Code baseline templates.
Concept

Author a reusable Terraform module template that expresses encryption, no public IPs, least-privilege IAM, and restricted egress. Review and statically validate the template here; mandatory deployment and conformance enforcement belong to AID-M-005.002.

Terraform module (minimal, runnable)
# File: terraform/modules/secure_ml_instance/variables.tf
variable "instance_type" {
  type = string
}
variable "vpc_id" {
  type = string
}
variable "subnet_id" {
  type = string
}
variable "kms_key_id" {
  type = string
}
variable "name_prefix" {
  type = string
}
variable "ami_id" {
  type = string
  validation {
    condition     = can(regex("^ami-[0-9a-f]{8,17}$", var.ami_id))
    error_message = "ami_id must be an explicitly reviewed immutable AMI ID"
  }
}
# File: terraform/modules/secure_ml_instance/main.tf
resource "aws_security_group" "ml_training_sg" {
  name_prefix = "${var.name_prefix}-sg-"
  vpc_id      = var.vpc_id
  # No inbound by default
  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["10.0.0.0/8"]
  }
}

resource "aws_iam_role" "ml_training_role" {
  name               = "${var.name_prefix}-role"
  assume_role_policy = data.aws_iam_policy_document.ec2_assume.json
}

data "aws_iam_policy_document" "ec2_assume" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

resource "aws_iam_instance_profile" "profile" {
  name = "${var.name_prefix}-profile"
  role = aws_iam_role.ml_training_role.name
}

resource "aws_instance" "ml_training" {
  ami                         = var.ami_id
  instance_type               = var.instance_type
  subnet_id                   = var.subnet_id
  vpc_security_group_ids      = [aws_security_group.ml_training_sg.id]
  associate_public_ip_address = false
  monitoring                  = true
  iam_instance_profile        = aws_iam_instance_profile.profile.name

  root_block_device {
    encrypted  = true
    kms_key_id = var.kms_key_id
  }

  metadata_options {
    http_tokens = "required"   # IMDSv2
  }
}
# File: terraform/envs/prod/main.tf (usage)
module "secure_ml_instance" {
  source       = "../../modules/secure_ml_instance"
  name_prefix  = "fraud-train"
  instance_type = "m6i.xlarge"
  vpc_id       = var.vpc_id
  subnet_id    = var.subnet_id
  kms_key_id   = var.kms_key_id
  ami_id       = "ami-0123456789abcdef0" # replace through reviewed region-specific lock data
}

Action: Record the reviewed module version, provider lock file, region-specific AMI ID, and static-validation result as authoring evidence. Placeholder IDs, most_recent lookups, floating module sources, or missing .terraform.lock.hcl make the template INSUFFICIENT_DATA; AID-M-005.002 owns publication and enforcement.

AID-M-005.001-G002

Author and review a digest-pinned, dependency-locked minimal container template.
Concept

Author a multi-stage, non-root template that copies only runtime artifacts. Every base must be supplied as a reviewed full digest reference and every Python dependency must come from a hash-locked file; missing locks are an authoring validation failure.

Multi-stage Dockerfile (runnable)
# File: Dockerfile
ARG PYTHON_BUILD_IMAGE
ARG DISTROLESS_RUNTIME_IMAGE
FROM ${PYTHON_BUILD_IMAGE} AS build
WORKDIR /app
COPY requirements.lock .
RUN pip install --no-cache-dir --require-hashes -r requirements.lock
COPY src/ src/

FROM ${DISTROLESS_RUNTIME_IMAGE}
WORKDIR /app
COPY --from=build /usr/local/lib/python3.10 /usr/local/lib/python3.10
COPY --from=build /app/src /app/src
USER 65532:65532
ENV PYTHONPATH=/usr/local/lib/python3.10/site-packages
ENTRYPOINT ["/usr/bin/python3","/app/src/main.py"]

Authoring validation: Require both build arguments to match ^[^@]+@sha256:[a-f0-9]{64}$, require every line in requirements.lock to carry an approved hash, build the template, and record the resulting image digest and static scan. A tag-only base, missing argument, floating dependency, or unhashed requirement is INSUFFICIENT_DATA. AID-M-005.002 owns registry publication, admission enforcement, and release measurement.

AID-M-005.001-G003

Author and review benchmark-traceable cluster policy templates without performing deployment enforcement.
Concept

Translate an explicitly versioned benchmark requirement into a reviewed candidate policy template and maintain its control-to-policy traceability. Applying the template, evaluating live resources, and measuring conformance belong to AID-M-005.002.

Kyverno policy to drop NET_RAW (maps to CIS K8s 5.2.x)
# File: k8s/policies/deny-net-raw.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: drop-net-raw
spec:
  rules:
  - name: require-drop-net-raw
    match:
      any:
      - resources:
          kinds: [Pod]
    validate:
      message: "Containers must drop NET_RAW capability"
      pattern:
        spec:
          containers:
          - securityContext:
              capabilities:
                drop: ["NET_RAW"]
Pod Security Admission namespace template
# File: k8s/templates/ai-workloads-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: ai-workloads
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: "v1.30"

Action: Record the exact benchmark edition, Kubernetes API/minor version, template digest, policy-engine schema validation, and reviewer decision. A floating latest version, missing benchmark clause, unsupported cluster version, or unresolved value is INSUFFICIENT_DATA. AID-M-005.002 owns applying these templates and collecting live enforcement evidence.

AID-M-005.001-G004

Author and validate a digest-pinnable, dependency-locked secure Jupyter Server image template.
Concept:

Jupyter Server 2 moved authentication settings from legacy NotebookApp and deprecated ServerApp.password/ServerApp.token fields to identity-provider configuration. Author the template with authentication enabled, a runtime-mounted password hash, localhost binding behind an authenticated same-pod proxy, and no baked credential. Deployment and admission enforcement remain in AID-M-005.002.

Step 1: Configure the current Jupyter Server identity provider
# File: jupyter/jupyter_server_config.py
from pathlib import Path

from traitlets.config import get_config


c = get_config()
password_hash_path = Path("/run/secrets/jupyter_password_hash")
if not password_hash_path.is_file():
    raise RuntimeError("Jupyter password hash secret is missing")

password_hash = password_hash_path.read_text(encoding="utf-8").strip()
if not password_hash.startswith("argon2:"):
    raise RuntimeError("Jupyter password hash must use Argon2")

c.ServerApp.identity_provider_class = "jupyter_server.auth.identity.PasswordIdentityProvider"
c.PasswordIdentityProvider.hashed_password = password_hash
c.PasswordIdentityProvider.password_required = True
c.PasswordIdentityProvider.allow_password_change = False

c.ServerApp.ip = "127.0.0.1"
c.ServerApp.port = 8888
c.ServerApp.open_browser = False
c.ServerApp.allow_remote_access = False
c.ServerApp.allow_root = False
c.ServerApp.allow_origin = ""
c.ServerApp.allow_credentials = False
c.ServerApp.disable_check_xsrf = False
c.ServerApp.trust_xheaders = False
c.ServerApp.terminals_enabled = False
c.ServerApp.root_dir = "/home/nbuser/work"

Generate the Argon2 hash interactively with jupyter server password or jupyter_server.auth.passwd(), then place only the resulting hash in the runtime secret. Do not set any token or password field to an empty string; that can disable authentication.

Step 2: Validate a non-root image template without credentials
# File: Dockerfile
ARG JUPYTER_BASE_IMAGE
FROM ${JUPYTER_BASE_IMAGE}

COPY jupyter/jupyter-requirements.lock /tmp/jupyter-requirements.lock
RUN pip install --no-cache-dir --require-hashes -r /tmp/jupyter-requirements.lock  && rm /tmp/jupyter-requirements.lock  && useradd --create-home --uid 10001 nbuser  && install -d -o 10001 -g 10001 /home/nbuser/.jupyter /home/nbuser/work

COPY --chown=10001:10001 jupyter/jupyter_server_config.py /home/nbuser/.jupyter/jupyter_server_config.py
USER 10001:10001
WORKDIR /home/nbuser/work
EXPOSE 8888
CMD ["jupyter", "server", "--config=/home/nbuser/.jupyter/jupyter_server_config.py"]
Step 3: Author the deployment boundary and acceptance tests

Template a read-only mount for /run/secrets/jupyter_password_hash, a read-only root filesystem, dropped Linux capabilities, and an authenticated same-pod proxy or JupyterHub path to the localhost listener. Author an admission rule that rejects arbitrary notebook images and root containers, but leave its enforcement to AID-M-005.002.

Authoring validation: Require JUPYTER_BASE_IMAGE to be a full @sha256: reference, require every Jupyter dependency and transitive dependency in jupyter-requirements.lock to have an approved hash, build the template, inspect the effective Jupyter configuration, and define tests for direct-port isolation, unauthenticated challenge, and XSRF rejection. A mutable tag, unresolved base argument, unlocked dependency, legacy auth trait, or missing test is INSUFFICIENT_DATA.

Action: Version and review the image template, dependency lock, expected effective configuration, and acceptance-test definitions. AID-M-005.002 owns publication, admission, execution of release tests, and live conformance evidence.

Open-source tools

Source-available / open-weight tools

Commercial / hosted tools

Threat mappings

MITRE ATLAS

MAESTRO

OWASP LLM Top 10 2026

OWASP ML Top 10 2023

OWASP Top 10 for Agentic Applications 2026

NIST Adversarial Machine Learning 2025

Cisco Integrated AI Security and Safety Framework

Google Secure AI Framework 2.0 - Risks

Databricks AI Security Framework 3.0

AID-M-005.001: Secure Configuration Template Development | AIDEFEND

Loading interactive view…

A Practical Knowledge Base for AI Security Defenses

Version