You have built the pipeline. Secret scanning runs on every commit. SAST catches vulnerable code patterns before merge. Trivy blocks images with critical CVEs. Checkov rejects misconfigured Terraform. And then a zero-day vulnerability is discovered in a library you depend on. The package was not yet in any CVE database when your last scan ran. Your pipeline passed. The image is deployed. Production is running code that nobody flagged. Or a developer on your team provisions an EC2 instance with a public security group for "quick testing" — directly via the console, not through your Terraform pipeline, so IaC scanning never saw it. Or an attacker compromises an npm package you depend on at the build system level — the package maintainer's account was phished. The malicious code is in your dependencies but not yet in any public CVE feed. **These are the scenarios that pipeline security alone does not cover.** This module maps the tools and practices that fill those gaps. ### What This Module Covers and What It Does Not Covered here: Threat modeling — finding risks before they are coded Secrets management at scale — Vault and AWS Secrets Manager in depth Cloud security — GuardDuty, Security Hub, AWS Config Runtime security — Falco and container behavior monitoring Supply chain security — SBOMs, Cosign, Kyverno, SLSA SIEM fundamentals — what to collect and correlate Compliance automation — SOC 2 and ISO 27001 in a DevSecOps pipeline Not covered here — separate modules exist for: Network security and Zero Trust architecture Penetration testing and red team operations Incident response playbooks Application security engineering (secure code patterns in depth) ---
Most security problems are predictable. A login form will be tested with brute force. An API that accepts user input will be probed for injection. An S3 bucket with public permissions will be discovered by automated scanners within hours of creation. **Threat modeling is the practice of thinking through these predictable risks before you write a single line of code — while the cost to fix is still zero.** ### Why Teams Skip This (and Why That Is a Mistake) The most common reason teams skip threat modeling is that it sounds like a heavy, formal process requiring a security specialist. In reality, a 30-minute conversation before building a feature catches most of the obvious problems — and shapes design decisions before they are hard to change. Asking "what happens if someone intercepts this request?" before building a payment feature takes 10 seconds. Answering that question after you have deployed, tested, and integrated the feature takes days. ### The STRIDE Framework STRIDE is the most widely used threat modeling framework. Each letter represents a category of attack to think through when reviewing a design: | Letter | Threat Category | Real Example | |:-------|:---------------|:-------------| | **S** | Spoofing | Attacker fakes another user's identity in a Razorpay payment request | | **T** | Tampering | Attacker modifies order total during checkout via a proxy | | **R** | Repudiation | User denies making a transaction — no audit log exists to prove otherwise | | **I** | Information Disclosure | Stack trace exposes database schema in an API error response | | **D** | Denial of Service | IRCTC booking API flooded with requests during Tatkal opening | | **E** | Elevation of Privilege | Normal user accesses admin panel because authorization check was missing | ### How to Run a Basic Threat Modeling Session You need a whiteboard, 30 minutes, and the people building the feature. No special tool required. Step 1 — Draw what you are building Boxes for each service, database, user, and external API Arrows showing where data flows between components Step 2 — For each arrow (data in transit), ask: What data is crossing here? Can the sender be faked? Is it encrypted in transit? Step 3 — For each box (data at rest), ask: Who has access to this? Is anything sensitive stored here? What happens if this is compromised? Step 4 — For each risk found, decide: Accept — low risk, documented decision Mitigate — add a control (encryption, rate limiting, auth check) Eliminate — redesign to remove the risk entirely A photo of the whiteboard added to the feature ticket is enough documentation. The goal is to ask the questions, not produce a formal report. > 💡 **Tip:** The right moment for threat modeling is right after requirements are written and before coding starts. Block 30 minutes in the sprint planning meeting. Teams that make this a habit stop finding security bugs in production within 6 months. ### Threat Modeling for a Real Scenario Imagine you are building an API that lets Swiggy delivery partners upload photos of delivered orders: Data flow diagram: Partner mobile app → API Gateway → Upload Service → S3 bucket → CDN Applying STRIDE: Spoofing: Can anyone upload as a different delivery partner? Fix: require JWT token with partner ID, validate on upload service Tampering: Can a partner modify the S3 object after uploading? Fix: make the S3 bucket write-once, restrict object-level permissions Information Disclosure: Could photos of one partner's deliveries be visible to another? Fix: generate pre-signed URLs with expiry — never expose raw S3 URLs Denial of Service: Could a bad actor upload 10GB files continuously? Fix: enforce file size limits at API Gateway, rate limit per partner ID Elevation of Privilege: Can a partner access photos from orders they did not deliver? Fix: validate that the partner ID in the JWT matches the order's assigned partner This exercise takes 20 minutes and produces a concrete list of controls to build. ---
Every application needs credentials. The question is not whether you have secrets — it is whether you manage them securely. The two most widely used tools for this are HashiCorp Vault and AWS Secrets Manager. ### Why Environment Variables Are Not Enough The problem with environment variables: No audit trail — who set this? When was it last changed? What is the current value? No rotation — the credential stays the same forever until someone manually changes it Easy to accidentally log — many frameworks log environment on startup or in crash reports No access control — every process on the host sees the same environment What secrets management adds: Centralized storage with encryption at rest Fine-grained access control — only specific services can read specific secrets Audit logging — every read and write is recorded Automatic rotation — credentials change on a schedule without manual work Dynamic secrets — generate short-lived credentials on demand ### HashiCorp Vault — Core Concepts Vault is the most widely used secrets management platform. It is self-hosted (or available as HCP Vault, a managed cloud service). **Secret Engine** is where secrets live. Vault has multiple secret engine types: * `kv` — key-value store for static secrets (passwords, API keys) * `database` — generates dynamic credentials for databases on demand * `aws` — generates temporary AWS IAM credentials * `pki` — issues and revokes TLS certificates **Auth Method** is how clients prove their identity before Vault grants access: * Token — simplest, used for testing * AWS IAM — EC2 instances and Lambda functions authenticate using their IAM role * Kubernetes — pods authenticate using their service account JWT **Policy** controls what an authenticated client can do: ```bash ## A policy that allows reading the database secret only path "secret/data/devops-network/database" { capabilities = ["read"] } ``` **Lease** is how long a dynamic credential is valid. When the lease expires, the credential is automatically deleted from the database. ### Vault — Common Operations ```bash ## Start Vault in dev mode for local testing (not for production) vault server -dev ## Write a secret vault kv put secret/devops-network/database \ username=appuser \ password=Str0ngP@ssword123 ## Read a secret vault kv get secret/devops-network/database ## Read only the password value vault kv get -field=password secret/devops-network/database ## Enable the database secret engine vault secrets enable database ## Configure Vault to connect to Postgres and generate credentials vault write database/config/prod-postgres \ plugin_name=postgresql-database-plugin \ allowed_roles="app-role" \ connection_url="postgresql://{{username}}:{{password}}@prod-db.ap-south-1.rds.amazonaws.com:5432/appdb" \ username="vault-admin" \ password="VaultAdminPassword" ## Create a role that generates temporary credentials with 1-hour TTL vault write database/roles/app-role \ db_name=prod-postgres \ creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \ default_ttl="1h" \ max_ttl="24h" ## Generate a temporary credential on demand vault read database/creds/app-role ``` The last command creates a real Postgres user that expires in 1 hour. No long-lived database passwords exist anywhere. This is **dynamic secrets** — the most powerful Vault feature. ### Vault in Kubernetes — Agent Sidecar Pattern Vault Agent runs as a sidecar container alongside your application. It authenticates to Vault, fetches secrets, and writes them to a shared volume. Your application reads the secret from a file — it never talks to Vault directly. ```yaml ## Annotate your pod to inject the Vault agent sidecar apiVersion: v1 kind: Pod metadata: name: backend-api annotations: vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "app-role" vault.hashicorp.com/agent-inject-secret-database.txt: "secret/data/devops-network/database" spec: serviceAccountName: backend-api-sa ## This SA authenticates to Vault via Kubernetes auth containers: - name: backend-api image: registry.example.com/backend-api:abc12345 ## The secret appears at /vault/secrets/database.txt ## Your app reads it as a file — never as an environment variable ``` > 📌 **Remember:** Dynamic secrets are Vault's strongest feature. If a credential is stolen, it expires automatically in 1 hour. Compare that to rotating a hardcoded database password — which requires code changes, deployments, and coordination across every service that uses it. ### AWS Secrets Manager — When You Are Already on AWS AWS Secrets Manager is the managed alternative to self-hosted Vault. No server to run, native IAM integration, and automatic rotation built in. ```bash ## Create a secret aws secretsmanager create-secret \ --name devops-network/database \ --region ap-south-1 \ --secret-string '{"username":"appuser","password":"Str0ngP@ssword123"}' ## Retrieve a secret value aws secretsmanager get-secret-value \ --secret-id devops-network/database \ --region ap-south-1 \ --query SecretString \ --output text ## Enable automatic rotation — Secrets Manager rotates the password every 30 days ## and updates the RDS instance automatically aws secretsmanager rotate-secret \ --secret-id devops-network/database \ --rotation-rules AutomaticallyAfterDays=30 ``` ### External Secrets Operator — Syncing Cloud Secrets into Kubernetes Instead of Vault's agent sidecar, the External Secrets Operator synchronizes secrets from AWS Secrets Manager into Kubernetes Secret objects: ```yaml ## ClusterSecretStore — defines connection to AWS Secrets Manager apiVersion: external-secrets.io/v1beta1 kind: ClusterSecretStore metadata: name: aws-secrets-manager spec: provider: aws: service: SecretsManager region: ap-south-1 auth: jwt: serviceAccountRef: name: external-secrets-sa namespace: external-secrets --- ## ExternalSecret — syncs a specific secret from AWS into Kubernetes apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: database-credentials namespace: devops-network spec: refreshInterval: 1h ## Re-sync every hour secretStoreRef: name: aws-secrets-manager kind: ClusterSecretStore target: name: db-credentials ## Name of the Kubernetes Secret that gets created data: - secretKey: password remoteRef: key: devops-network/database property: password ``` The result is a standard Kubernetes Secret object that your pods can mount — but its value comes from AWS Secrets Manager and rotates automatically. ### When to Use What | Scenario | Recommended Approach | |:---------|:--------------------| | AWS-native infrastructure | AWS Secrets Manager + External Secrets Operator | | Multi-cloud or self-hosted | HashiCorp Vault + Agent Sidecar | | Dynamic database credentials | Vault database secret engine | | Short-lived TLS certificates | Vault PKI secret engine | | CI/CD pipeline secrets | GitHub Actions Secrets or GitLab protected variables | | Local development | .env file (git-ignored) + dotenv library | ---
Cloud environments have a security layer that sits above your application and infrastructure code. Misconfigurations in AWS are responsible for a large percentage of real-world breaches — not sophisticated exploits, just resources left open that should have been locked down. ### The Shared Responsibility Model AWS divides security into two halves: AWS is responsible for: Physical security of data centers Hardware, networking, and hypervisor Security OF the cloud You are responsible for: What you put in the cloud and how you configure it IAM policies, security groups, encryption settings Patching your EC2 instances and container images Security IN the cloud Most cloud security incidents happen in your half — misconfigured S3 buckets, overly permissive IAM roles, security groups open to 0.0.0.0/0. ### AWS GuardDuty — Continuous Threat Detection GuardDuty monitors your AWS account continuously without any agent installation. It analyzes CloudTrail logs, VPC Flow Logs, and DNS query logs using machine learning and threat intelligence to detect: * Unusual API calls from foreign IP addresses or at unusual hours * Cryptocurrency mining behavior on EC2 instances * Data exfiltration patterns — unusually large data being sent out * Compromised EC2 instances communicating with known malicious IP addresses * Credential theft — API calls using compromised IAM keys ```bash ## Enable GuardDuty — takes 30 seconds, provides value immediately aws guardduty create-detector \ --enable \ --region ap-south-1 ## List findings in the last 24 hours aws guardduty list-findings \ --detector-id YOUR_DETECTOR_ID \ --finding-criteria '{"Criterion":{"updatedAt":{"Gte":1704067200}}}' ``` GuardDuty has a 30-day free trial and costs very little to run in most accounts. Enable it in every AWS account and every region you use. ### AWS Security Hub — One Dashboard for Everything Security Hub aggregates security findings from GuardDuty, Inspector, Macie, Firewall Manager, and third-party tools into a single dashboard with severity scores. Instead of checking five different services, you see all findings in one place. ```bash ## Enable Security Hub aws securityhub enable-security-hub \ --enable-default-standards \ --region ap-south-1 ## Enable the AWS Foundational Security Best Practices standard aws securityhub batch-enable-standards \ --standards-subscription-requests \ StandardsArn=arn:aws:securityhub:ap-south-1::standards/aws-foundational-security-best-practices/v/1.0.0 ``` Security Hub also runs automated compliance checks against the AWS Foundational Security Best Practices standard — flagging things like MFA not enabled, S3 buckets without server-side encryption, and security groups with unrestricted inbound access. ### AWS Config — Track Every Configuration Change AWS Config records the configuration state of every AWS resource over time. When something changes — a security group rule is added, an S3 bucket becomes public, an IAM policy is modified — Config captures it with a timestamp and the identity that made the change. ```bash ## Enable Config recording for all resources in a region aws configservice put-configuration-recorder \ --configuration-recorder \ name=default,roleARN=arn:aws:iam::111122223333:role/config-role \ --recording-group allSupported=true ## Create a Config rule that flags S3 buckets with public read access aws configservice put-config-rule \ --config-rule \ Name=s3-bucket-public-read-prohibited,\ Source={Owner=AWS,SourceIdentifier=S3_BUCKET_PUBLIC_READ_PROHIBITED} ``` Config rules can also auto-remediate. When a bucket becomes public, Config can automatically make it private again — using an SSM automation document triggered by the rule violation. ### AWS Macie — Find Sensitive Data in S3 Macie automatically discovers sensitive data stored in S3 — PII like Aadhaar numbers, PAN cards, credit card numbers, and credentials. It scans your buckets on a schedule and alerts you to buckets with sensitive data that are publicly accessible or unencrypted. ```bash ## Enable Macie aws macie2 enable-macie --region ap-south-1 ## Create a classification job to scan a specific bucket aws macie2 create-classification-job \ --job-type ONE_TIME \ --name "scan-user-data-bucket" \ --s3-job-definition \ bucketDefinitions=[{accountId=111122223333,buckets=[user-data-prod]}] ``` ### AWS Inspector — Continuous Vulnerability Scanning Inspector automatically scans EC2 instances and container images in ECR for CVEs and network exposure issues. Unlike running Trivy manually, Inspector scans continuously without you scheduling anything. ```bash ## Enable Inspector for EC2 and ECR aws inspector2 enable \ --resource-types EC2,ECR \ --region ap-south-1 ``` ### The Minimum Cloud Security Baseline ```bash ## Enable GuardDuty in every region you use aws guardduty create-detector --enable --region ap-south-1 ## Enable Security Hub with default standards aws securityhub enable-security-hub --enable-default-standards --region ap-south-1 ## Enable CloudTrail — logs every API call across all regions aws cloudtrail create-trail \ --name devops-network-audit-trail \ --s3-bucket-name devops-network-cloudtrail-logs \ --is-multi-region-trail aws cloudtrail start-logging --name devops-network-audit-trail ## Block public S3 access at the account level aws s3control put-public-access-block \ --account-id 111122223333 \ --public-access-block-configuration \ BlockPublicAcls=true,IgnorePublicAcls=true,\ BlockPublicPolicy=true,RestrictPublicBuckets=true ``` > 💡 **Tip:** Enable GuardDuty and Security Hub on day one of any new AWS account — both have free tiers and require zero configuration to start providing value. The combined monthly cost for a typical startup-scale account is under $50. A single breach costs far more. ---
Shipping securely is not the finish line. Once your application is running in production, you need visibility into what is happening — both for operational and security reasons. Vulnerabilities that SAST, SCA, and DAST never caught can still appear at runtime. ### What Runtime Security Covers What you need to detect while the app is running: A process inside a container spawning a shell (sign of a breach) A container reading sensitive files it should never touch Unexpected outbound network connections from a pod A user account making unusual API calls at 3 AM A privileged container trying to access the host filesystem None of these events appear in code scans or pre-deploy checks. They only exist when the application is running under real conditions. ### Falco — Container Runtime Security Falco is the most widely used open-source runtime security tool for Kubernetes. It runs as a DaemonSet on every node, monitoring system calls in real time. When a process inside a container does something that matches a security rule, Falco fires an alert. ```bash ## Install Falco using Helm helm repo add falcosecurity https://falcosecurity.github.io/charts helm install falco falcosecurity/falco \ --namespace falco \ --create-namespace \ --set falco.grpc.enabled=true \ --set falco.grpcOutput.enabled=true ``` Falco ships with a default ruleset covering the most critical behaviors. You can see rules that fire in real time: ```bash ## Follow Falco output kubectl logs -n falco -l app.kubernetes.io/name=falco -f ``` ### Writing Falco Rules ```yaml ## Alert if any process inside a container opens a shell - rule: Terminal Shell in Container desc: A shell was opened inside a running container — possible breach condition: > spawned_process and container and shell_procs and proc.tty != 0 output: > Shell opened in container (user=%user.name container=%container.name image=%container.image.repository shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline) priority: WARNING tags: [container, shell, mitre_execution] ## Alert if a container reads /etc/shadow (password hashes) - rule: Read Sensitive File in Container desc: A process in a container read a sensitive file condition: > open_read and container and sensitive_files output: > Sensitive file opened for reading (user=%user.name file=%fd.name container=%container.name image=%container.image.repository) priority: ERROR ## Alert on unexpected outbound connections from certain namespaces - rule: Unexpected Outbound Connection desc: A container in the payments namespace made an unexpected outbound connection condition: > outbound and container and k8s.ns.name="payments" and not fd.sip in (allowed_payment_gateway_ips) output: > Unexpected outbound connection from payments namespace (container=%container.name destination=%fd.sip:%fd.sport) priority: CRITICAL ``` ### What Falco Detects by Default The default Falco ruleset flags behaviors like: shell spawned in a container, write to `/etc` or `/usr` inside a container, sensitive file read (`/etc/shadow`, `/etc/kubernetes/admin.conf`), outbound network connections from containers that should not have them, and containers running with the privileged flag. > 📌 **Remember:** Falco alerts on behavior, not known CVEs. A zero-day exploit that has never been seen before will still trigger Falco if it spawns a shell or reads a sensitive file. This is why runtime security and pre-deploy scanning are complementary — not redundant. ---
Modern software is not just the code you write. It is the open-source libraries you depend on, the base images your containers are built from, the CI/CD tools in your pipeline, and the build systems that produce your artifacts. All of these are potential attack vectors. ### The Supply Chain Attack Problem A supply chain attack targets the tools and dependencies used to build software rather than the software itself. If an attacker compromises a popular npm package, they can inject malicious code into thousands of applications that depend on it — without ever attacking those applications directly. Three real events that shaped this domain: * **SolarWinds (2020)** — the build system was compromised and malicious code was injected into signed software updates, delivered to 18,000 organizations as a trusted update * **Log4Shell (2021)** — a single widely-used library had a critical remote code execution vulnerability that affected thousands of unrelated applications * **XZ Utils (2024)** — a malicious contributor spent two years building trust before injecting a backdoor into a core Linux utility that ships in most Linux distributions ### SBOM — Software Bill of Materials An SBOM is a complete list of every component in your software — every library, every dependency, every version. Think of it as an ingredient list for your application. Without an SBOM, when a new CVE is announced you have to manually check whether any of your applications is affected. With an SBOM, you query it like a database. ```bash ## Install Syft curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin ## Generate an SBOM for a Docker image in SPDX format syft devops-network-app:latest -o spdx-json > sbom.json ## Generate for a directory syft dir:./src -o cyclonedx-json > sbom-cyclonedx.json ## Scan the SBOM for vulnerabilities using Grype grype sbom:./sbom.json ``` ### Image Signing with Cosign Image signing proves that a container image was built by your trusted CI/CD pipeline and has not been modified since. If someone pushes a malicious image to your registry, signature verification will reject it before it can be deployed. ```bash ## Generate a key pair for signing cosign generate-key-pair ## Sign an image after building and pushing it cosign sign --key cosign.key \ ghcr.io/devops-network/backend-api:abc12345sha ## Verify a signature before deploying cosign verify --key cosign.pub \ ghcr.io/devops-network/backend-api:abc12345sha ``` Add signing to your GitHub Actions pipeline: ```yaml ## After building and pushing the image - name: Sign container image with Cosign env: COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }} run: | cosign sign --key env://COSIGN_PRIVATE_KEY \ ghcr.io/devops-network/backend-api:${{ github.sha }} ``` ### Enforcing Signed Images in Kubernetes with Kyverno Kyverno is a Kubernetes-native policy engine. This policy rejects any pod that tries to run an unsigned image: ```yaml apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-signed-images spec: validationFailureAction: Enforce background: false rules: - name: check-image-signature match: any: - resources: kinds: [Pod] namespaces: [production, staging] verifyImages: - imageReferences: - "ghcr.io/devops-network/*" attestors: - entries: - keys: publicKeys: |- -----BEGIN PUBLIC KEY----- YOUR_COSIGN_PUBLIC_KEY_HERE -----END PUBLIC KEY----- ``` Any pod admission attempt in the `production` or `staging` namespaces with an unsigned image is now rejected at the Kubernetes API server level — before the pod is even created. ### Pinning Dependencies A key supply chain risk is mutable references — using a tag like `latest` or `^4.18.2` means your build can pick up different code on different days. ```dockerfile ## Weak: tag is mutable, image can change without warning FROM node:20 ## Strong: pinned to an immutable digest — always the exact same bytes FROM node:20@sha256:a1b2c3d4e5f6789012345678901234567890abcdef ``` ```json { "dependencies": { "express": "4.18.2" } } ``` Pinning to exact versions (not ranges like `^4.18.2`) means a malicious update to a dependency cannot silently enter your build. ### SLSA — Supply Chain Levels for Software Artifacts SLSA (pronounced "salsa") is a framework for supply chain security maturity, similar to how STRIDE provides a framework for threat categories. It defines four levels: SLSA Level 1: Build process is documented and scripted SLSA Level 2: Build is hosted on a version-controlled build service with provenance SLSA Level 3: Build is isolated and reproducible with verified provenance SLSA Level 4: Two-party review for all changes, hermetic builds Most production systems target SLSA Level 2 or 3. GitHub Actions and Google Cloud Build have built-in support for generating SLSA provenance metadata. ### Supply Chain Tool Summary | Tool | What It Does | |:-----|:------------| | **Cosign** | Sign and verify container images | | **Syft** | Generate SBOMs for images and directories | | **Grype** | Scan SBOMs for vulnerabilities | | **Kyverno** | Policy engine — enforce security rules at pod admission time | | **Ratify** | Enforce image signature verification in Kubernetes (alternative to Kyverno) | | **SLSA** | Framework for supply chain maturity levels | > 💡 **Tip:** Start with Syft for SBOM generation and Cosign for image signing — these two give you the foundation for a verifiable supply chain. Add Kyverno enforcement once you have signing working reliably in all your pipelines. ---
You have built the pipeline. Secret scanning runs on every commit. SAST catches vulnerable code patterns before merge. T...
Most security problems are predictable. A login form will be tested with brute force. An API that accepts user input wil...
Every application needs credentials. The question is not whether you have secrets — it is whether you manage them secure...
Cloud environments have a security layer that sits above your application and infrastructure code. Misconfigurations in ...
Shipping securely is not the finish line. Once your application is running in production, you need visibility into what ...
Modern software is not just the code you write. It is the open-source libraries you depend on, the base images your cont...
A SIEM (Security Information and Event Management) collects logs from every system — application logs, AWS CloudTrail, K...
Compliance frameworks like SOC 2, ISO 27001, and PCI-DSS define security standards organizations must meet. Without DevS...
Full Tool Map Area Tool What It Does Secrets management HashiCorp Vault Dynamic credentials, multi-cloud, fine-grained p...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.