What can we help you with?
AppSec Engineer — Cloud & Container Security Specialist
AppSec Engineer — Cloud & Container Security Specialist
Role Overview
This engineer owns the security of the compute substrate: containers, orchestration platforms, cloud control planes, and the infrastructure-as-code that defines them. Misconfigured cloud resources and container escapes are primary vectors for lateral movement and data exfiltration.
① SHARED CORE COMPETENCIES (1/3)
These competencies are identical across all five AppSec engineer roles.
1.1 Threat Modeling (STRIDE / PASTA)
- Facilitate threat modeling sessions against architecture diagrams and data-flow diagrams
- Map assets → trust boundaries → threats using STRIDE categories:
- Spoofing · Tampering · Repudiation · Information Disclosure · DoS · Elevation
- Produce threat model artifacts: DFD, threat register, mitigations table
- PASTA for risk-quantified models
- Output: ranked threat list with likelihood × impact scores
1.2 Secure Code Review
- Review PRs for OWASP Top 10 and CWE Top 25 violations
- Identify: injection flaws, insecure deserialization, broken auth, sensitive data exposure
- Provide remediation guidance with corrected code snippets
- Distinguish false positives from true findings; assign severity (Critical/High/Med/Low)
- Tools: manual review + semgrep rules, CodeQL queries
1.3 Vulnerability Assessment & CVSS Scoring
- Triage CVEs from scanner output; calculate CVSS v3.1 Base + Environmental scores
- Prioritize using EPSS alongside CVSS
- Map findings to business risk; generate executive-ready vuln summary reports
- Track remediation SLAs: Critical ≤24h, High ≤7d, Medium ≤30d, Low ≤90d
② SPECIALIST DOMAIN — Cloud & Container Security (2/3)
2.1 Container Security
- Dockerfile hardening checklist:
[ ] Non-root USER directive (UID ≥ 1000)
[ ] Minimal base image (distroless / alpine)
[ ] No secrets in ENV or ARG at build time
[ ] Multi-stage build: builder ≠ runtime image
[ ] COPY --chown instead of RUN chown
[ ] Read-only filesystem where possible
[ ] No SUID/SGID binaries in final layer
[ ] Pinned digest for base images (not :latest)
- Image scanning: Trivy, Grype, Snyk Container — scan in CI and registry
- Registry security: private registry with image signing (cosign), vulnerability policy gates
- Runtime defense: Falco rules for: exec in container, unexpected outbound connections, /etc/passwd writes
2.2 Kubernetes Security Hardening
- Pod Security Standards: enforce Restricted profile in production namespaces
- Security context per workload:
securityContext:
runAsNonRoot: true
runAsUser: 10001
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
- Network Policies: default-deny-all baseline; explicit ingress/egress allowlists
- RBAC audit: identify
cluster-adminbindings, wildcard verbs, overbroad service account permissions - Secrets management: no secrets in ConfigMaps; use ExternalSecrets Operator or CSI driver
- Admission controllers: OPA Gatekeeper / Kyverno policies for policy-as-code enforcement
- etcd encryption at rest; audit log retention
- API server: disable anonymous auth, enable audit logging, restrict bind addresses
2.3 Infrastructure as Code (IaC) Security
- Terraform security scanning: Checkov, tfsec, Terrascan
- Common Terraform misconfigurations:
- S3 buckets:
block_public_accessnot fully enabled - Security groups:
0.0.0.0/0ingress on port 22/3389 - RDS:
publicly_accessible = true - CloudTrail: logging disabled or trail not in all regions
- KMS: key rotation disabled
- Helm chart security: image digest pinning, securityContext requirements, no hostNetwork
- GitOps security: Flux/ArgoCD RBAC, repository integrity verification
2.4 Cloud IAM Least Privilege
- AWS: IAM policy analysis with Access Analyzer; identify
:policies, unused roles - Use permission boundaries for delegated admin; SCPs for OU-level guardrails
- Instance metadata service: enforce IMDSv2 (
HttpTokens: required) - GCP: Workload Identity for GKE; avoid service account key files
- Azure: Managed Identity over service principals with client secrets
- Cross-account access: review trust policies for condition keys (ExternalId, aws:PrincipalOrgID)
- Credential hygiene: regular access key rotation, unused access key detection
2.5 Secrets Management
- Architecture: centralized Vault or cloud-native secrets manager; no secrets in code/config
- Vault patterns: AppRole + response wrapping, Kubernetes auth method, dynamic credentials
- Secret rotation: automated rotation for DB credentials, API keys, TLS certificates
- SOPS for IaC-adjacent secrets: KMS-encrypted secrets committed to Git
- Audit: detect secrets drift, access anomalies, unused secrets accumulation
2.6 Cloud Security Posture Management (CSPM)
- Tools: AWS Security Hub, Prisma Cloud, Orca Security, Wiz
- Benchmark alignment: CIS Benchmarks (AWS/GCP/Azure/K8s), NIST CSF
- Misconfiguration detection: publicly exposed storage, unencrypted databases, open security groups
- Asset inventory: maintain up-to-date cloud resource inventory; detect shadow assets
- Continuous compliance: drift detection and auto-remediation (Lambda/Cloud Functions)
③ TEST SUITES
Unit Tests
Discrete checks against IaC modules and security policy logic.
unit_tests:
- id: UT-CCS-001
name: "Terraform S3 Module — Public Access Blocked"
description: >
Assert that the organization's S3 Terraform module always sets all four
block_public_access attributes to true.
input:
module: "modules/storage/s3"
test_config: "tests/fixtures/s3_default.tfvars"
tool: "checkov"
assertions:
- check_id: "CKV_AWS_55" # block_public_acls
pass: true
- check_id: "CKV_AWS_56" # block_public_policy
pass: true
- check_id: "CKV_AWS_57" # ignore_public_acls
pass: true
- check_id: "CKV_AWS_54" # restrict_public_buckets
pass: true
- id: UT-CCS-002
name: "Dockerfile — Non-Root User Enforced"
description: >
Parse Dockerfile; assert USER instruction is present and UID is not 0.
input:
dockerfile: "tests/fixtures/Dockerfile.app"
assertions:
- user_instruction_present: true
- user_is_root: false
- uid_gte: 1000
- id: UT-CCS-003
name: "K8s Pod Spec — Privilege Escalation Disabled"
description: >
Assert that all Deployment manifests in the repository set
allowPrivilegeEscalation: false in their container securityContext.
input:
manifest_glob: "k8s/**/*.yaml"
tool: "kyverno CLI / conftest"
assertions:
- all_containers_have_allow_privilege_escalation_false: true
- non_compliant_count: 0
- id: UT-CCS-004
name: "Vault Policy — Least Privilege for App Role"
description: >
Assert that the 'payment-service' Vault policy does not include
wildcard paths or 'delete' capability on secret/ mounts.
input:
policy_file: "vault/policies/payment-service.hcl"
assertions:
- no_wildcard_paths: true
- no_delete_capability_on_secrets: true
- paths_limited_to_service_prefix: true
Integration Tests
Security controls verified across real infrastructure components.
integration_tests:
- id: IT-CCS-001
name: "Container Runtime — Falco Detects exec in Container"
description: >
Run a test container; execute a shell command inside it; assert Falco
generates a 'Terminal shell in container' alert within 5 seconds.
steps:
- launch_test_pod: "tests/fixtures/test-pod.yaml"
- exec_command_in_pod: "/bin/sh -c id"
- wait_for_falco_alert_seconds: 5
assertions:
- alert_generated: true
- alert_rule: "Terminal shell in container"
- alert_priority: "WARNING"
environment: "k8s-security-sandbox"
- id: IT-CCS-002
name: "Network Policy — Pod Cannot Reach Disallowed Namespace"
description: >
From a pod in the 'app' namespace, attempt to connect to a pod in
the 'data' namespace on port 5432; assert connection is refused by
network policy (not just timeout).
steps:
- source_pod_namespace: "app"
- target_pod_namespace: "data"
- target_port: 5432
assertions:
- connection_result: "refused"
- network_policy_drop_count_incremented: true
- id: IT-CCS-003
name: "IMDSv2 Enforced — IMDSv1 Request Blocked"
description: >
From an EC2 instance, attempt to fetch metadata using IMDSv1 (no token);
assert HTTP 401 is returned from metadata service.
steps:
- instance_type: "ec2-test"
- request_type: "IMDSv1-no-token"
- url: "http://169.254.169.254/latest/meta-data/"
assertions:
- http_status: 401
- metadata_not_returned: true
- id: IT-CCS-004
name: "OPA Gatekeeper Rejects Privileged Pod"
description: >
Attempt to deploy a Pod with privileged: true; assert Gatekeeper
admission webhook rejects with a policy violation message.
steps:
- apply_manifest: "tests/fixtures/privileged-pod.yaml"
assertions:
- kubectl_exit_code: 1
- error_message_contains: ["gatekeeper", "privileged"]
- pod_not_created: true
Smoke Tests
Quick verification that cloud security controls are active in each environment.
smoke_tests:
- id: ST-CCS-001
name: "No Public S3 Buckets in Account"
description: "AWS account has zero publicly accessible S3 buckets."
command: >
aws s3api list-buckets --query 'Buckets[*].Name' --output text |
xargs -I{} aws s3api get-bucket-policy-status --bucket {} |
grep -c '"IsPublic": true'
expected_output: "0"
timeout_seconds: 60
- id: ST-CCS-002
name: "Falco Agent Running on All Nodes"
description: "Falco DaemonSet has all pods in Running state."
command: >
kubectl get ds falco -n falco -o jsonpath='{.status.numberReady}' &&
kubectl get ds falco -n falco -o jsonpath='{.status.desiredNumberScheduled}' |
awk '{if($1==$2) exit 0; else exit 1}'
expected_exit_code: 0
timeout_seconds: 30
- id: ST-CCS-003
name: "No Containers Running as Root in Production Namespace"
description: "All running pods in 'production' namespace use non-root UIDs."
command: >
kubectl get pods -n production -o jsonpath='{range .items[*]}{.spec.securityContext.runAsUser}{"\n"}{end}' |
awk '{if($1=="0" || $1=="") {found=1}} END {exit found}'
expected_exit_code: 0
timeout_seconds: 20
- id: ST-CCS-004
name: "CloudTrail Logging Active in All Regions"
description: "AWS CloudTrail has a multi-region trail with logging enabled."
command: >
aws cloudtrail describe-trails --include-shadow-trails |
jq '[.trailList[] | select(.IsMultiRegionTrail==true and .HasCustomEventSelectors==true)] | length > 0'
expected_output: "true"
timeout_seconds: 30
