Skip to content

AWS provider

The AWS provider uses a boto3.Session scoped to a single region. It supports named AWS CLI profiles via --profile and honors the AWS_ENDPOINT_URL environment variable (for LocalStack).

Services covered

Service Check IDs
CodeBuild CB-001..011
CodePipeline CP-001..007
CodeDeploy CD-001, CD-002, CD-003
ECR ECR-001..007
IAM IAM-001..008
PBAC (CodeBuild roles/VPC, pipeline role scoping) PBAC-001..005
S3 S3-001, S3-002, S3-003, S3-004, S3-005
CloudTrail CT-001, CT-002, CT-003
CloudWatch Logs CWL-001, CWL-002
CloudWatch Alarms CW-001
Secrets Manager SM-001, SM-002
CodeArtifact CA-001, CA-002, CA-003, CA-004
CodeCommit CCM-001, CCM-002, CCM-003
Lambda LMB-001, LMB-002, LMB-003, LMB-004
KMS KMS-001, KMS-002
SSM Parameter Store SSM-001, SSM-002
EventBridge EB-001, EB-002
AWS Signer SIGN-001, SIGN-002

Class-based vs rule-based. The original seven-service checks (CB/CP/CD/ECR/IAM/PBAC/S3-001..) live as monolithic classes under pipeline_check/core/checks/aws/*.py. Everything added in later phases. CT-, CWL-, SM-, CA-, CCM-, LMB-, KMS-, SSM-, EB-, SIGN-, CW-*, plus the CB-008+ / CP-005+ / ECR-006+ / IAM-007+ / PBAC-003+ series, lives as one-file-per-rule modules under pipeline_check/core/checks/aws/rules/, auto-discovered by AWSRuleChecks and sharing a cached ResourceCatalog so enumerations run once per scan.

Per-check detail below is sourced from the rule metadata under pipeline_check/core/checks/aws/rules/*.py (or the class docstrings for the original seven services).


CLI usage

# Default: scan us-east-1 with the ambient boto3 credential chain
pipeline_check --pipeline aws

# Pick a region
pipeline_check --pipeline aws --region eu-west-1

# Use a named AWS CLI profile (~/.aws/credentials)
pipeline_check --pipeline aws --profile prod-readonly

# Scope the scan to a single resource (e.g. one CodePipeline)
pipeline_check --pipeline aws --target my-release-pipeline

# Point boto3 at a local endpoint (LocalStack, etc.)
AWS_ENDPOINT_URL=http://localhost:4566 pipeline_check --pipeline aws

Credentials are resolved through the standard boto3 credential chain. Environment variables, ~/.aws/credentials, IMDS on EC2, container

credentials on ECS/Fargate, EKS Pod Identity, or SSO. To scan a different account, assume the role first with aws sts assume-role (or aws sso login / aws-vault) and export the resulting credentials, then invoke pipeline_check. The provider does not currently accept an --assume-role-arn flag.


Required IAM permissions

The scanner is read-only: every API call is a List*, Describe*, Get*, or BatchGet*. It never mutates state. Per-resource API calls are scoped to the active --region; IAM, S3, and STS are global and are reached through the same regional session.

Quickest path: managed policies

If you don't care about least-privilege, attach one of:

  • arn:aws:iam::aws:policy/SecurityAudit: covers everything below except a few Get*Policy calls; produces the same findings minus S3-005 (bucket policies), LMB-004 (Lambda resource policy), KMS-002 (key policy), CA-003/CA-004 (CodeArtifact policies), ECR-003 (repo policy), SM-002 (secret resource policy).
  • arn:aws:iam::aws:policy/ReadOnlyAccess: covers every action the scanner uses, plus a great deal more. Convenient but broad.

For least-privilege, use the policy below.

Permission map by service

Each row lists the check IDs that depend on the actions in that service. If you skip a service entirely, you can drop its row from the policy and the scanner will emit a <PREFIX>-000 degraded finding (INFO) for that service rather than failing.

Service Check IDs that need it Required actions
CodeBuild CB-001..011, PBAC-001 codebuild:ListProjects, codebuild:BatchGetProjects, codebuild:ListSourceCredentials
CodePipeline CP-001..007, PBAC-005 (also feeds S3 artifact-bucket discovery) codepipeline:ListPipelines, codepipeline:GetPipeline
CodeDeploy CD-001..003 codedeploy:ListApplications, codedeploy:ListDeploymentGroups, codedeploy:BatchGetDeploymentGroups
ECR ECR-001..007 ecr:DescribeRepositories, ecr:GetRepositoryPolicy, ecr:GetLifecyclePolicy, ecr:DescribePullThroughCacheRules
Inspector v2 ECR-007 inspector2:BatchGetAccountStatus
IAM IAM-001..008, PBAC-002, CICD-role enumeration iam:ListRoles, iam:ListUsers, iam:ListAccessKeys, iam:GetAccessKeyLastUsed, iam:ListRolePolicies, iam:GetRolePolicy, iam:ListAttachedRolePolicies, iam:GetPolicy, iam:GetPolicyVersion
CloudTrail CT-001..003 cloudtrail:DescribeTrails, cloudtrail:GetTrailStatus
CloudWatch Logs CWL-001, CWL-002 logs:DescribeLogGroups
CloudWatch Alarms CW-001 cloudwatch:DescribeAlarms
Secrets Manager SM-001, SM-002 secretsmanager:ListSecrets, secretsmanager:GetResourcePolicy
CodeArtifact CA-001..004 codeartifact:ListDomains, codeartifact:ListRepositories, codeartifact:DescribeRepository, codeartifact:GetDomainPermissionsPolicy, codeartifact:GetRepositoryPermissionsPolicy
CodeCommit CCM-001..003 codecommit:ListRepositories, codecommit:GetRepository, codecommit:GetRepositoryTriggers, codecommit:ListAssociatedApprovalRuleTemplatesForRepository
Lambda LMB-001..004 lambda:ListFunctions, lambda:GetFunctionCodeSigningConfig, lambda:GetFunctionUrlConfig, lambda:GetPolicy
KMS KMS-001, KMS-002 kms:ListKeys, kms:DescribeKey, kms:GetKeyRotationStatus, kms:GetKeyPolicy
SSM Parameter Store SSM-001, SSM-002 ssm:DescribeParameters
EventBridge EB-001, EB-002 events:ListRules, events:ListTargetsByRule
Signer SIGN-001, SIGN-002 signer:ListSigningProfiles
S3 S3-001..005 (artifact buckets discovered via CodePipeline) s3:GetPublicAccessBlock, s3:GetBucketEncryption, s3:GetBucketVersioning, s3:GetBucketLogging, s3:GetBucketPolicy
EC2 PBAC-003 (CodeBuild VPC security groups) ec2:DescribeSecurityGroups
STS CCM-003 (current account ID for cross-account trigger detection) sts:GetCallerIdentity

Copy-paste IAM policy

Save the following as pipeline-check-readonly.json and attach it to the role or user the scanner runs as. Every action is read-only and every resource is * because boto3 list/describe APIs do not accept resource-level conditions.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PipelineCheckReadOnlyScan",
      "Effect": "Allow",
      "Action": [
        "cloudtrail:DescribeTrails",
        "cloudtrail:GetTrailStatus",
        "cloudwatch:DescribeAlarms",
        "codeartifact:DescribeRepository",
        "codeartifact:GetDomainPermissionsPolicy",
        "codeartifact:GetRepositoryPermissionsPolicy",
        "codeartifact:ListDomains",
        "codeartifact:ListRepositories",
        "codebuild:BatchGetProjects",
        "codebuild:ListProjects",
        "codebuild:ListSourceCredentials",
        "codecommit:GetRepository",
        "codecommit:GetRepositoryTriggers",
        "codecommit:ListAssociatedApprovalRuleTemplatesForRepository",
        "codecommit:ListRepositories",
        "codedeploy:BatchGetDeploymentGroups",
        "codedeploy:ListApplications",
        "codedeploy:ListDeploymentGroups",
        "codepipeline:GetPipeline",
        "codepipeline:ListPipelines",
        "ec2:DescribeSecurityGroups",
        "ecr:DescribePullThroughCacheRules",
        "ecr:DescribeRepositories",
        "ecr:GetLifecyclePolicy",
        "ecr:GetRepositoryPolicy",
        "events:ListRules",
        "events:ListTargetsByRule",
        "iam:GetAccessKeyLastUsed",
        "iam:GetPolicy",
        "iam:GetPolicyVersion",
        "iam:GetRolePolicy",
        "iam:ListAccessKeys",
        "iam:ListAttachedRolePolicies",
        "iam:ListRolePolicies",
        "iam:ListRoles",
        "iam:ListUsers",
        "inspector2:BatchGetAccountStatus",
        "kms:DescribeKey",
        "kms:GetKeyPolicy",
        "kms:GetKeyRotationStatus",
        "kms:ListKeys",
        "lambda:GetFunctionCodeSigningConfig",
        "lambda:GetFunctionUrlConfig",
        "lambda:GetPolicy",
        "lambda:ListFunctions",
        "logs:DescribeLogGroups",
        "s3:GetBucketEncryption",
        "s3:GetBucketLogging",
        "s3:GetBucketPolicy",
        "s3:GetBucketVersioning",
        "s3:GetPublicAccessBlock",
        "secretsmanager:GetResourcePolicy",
        "secretsmanager:ListSecrets",
        "signer:ListSigningProfiles",
        "ssm:DescribeParameters",
        "sts:GetCallerIdentity"
      ],
      "Resource": "*"
    }
  ]
}

The policy is 2.5 KB, well inside the 6,144-byte limit for a customer-managed policy and the 10,240-byte limit for an inline role policy.

Trust policy for an IAM role

If you run the scanner from CI (e.g. GitHub Actions with OIDC), pair the policy above with a trust policy that lets your CI system assume the role. Below is an example for GitHub Actions OIDC; adapt for your provider.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
        }
      }
    }
  ]
}

Behavior when permissions are missing

The scanner does not fail closed when the principal lacks an action. Instead, the per-service enumeration records the error and the orchestrator emits one <PREFIX>-000 finding (INFO severity) per degraded service, for example CT-000, LMB-000, KMS-000. Every rule that depends on that service is suppressed for the run. Operators can therefore see exactly which permission gaps are masking findings.

Two exceptions are tolerated silently because their endpoints are optional:

  • ecr:DescribePullThroughCacheRules: not all regions/accounts have PTC; only ECR-006 is suppressed if it fails.
  • inspector2:BatchGetAccountStatus: only ECR-007 is suppressed if Inspector v2 is not enabled in the region.

CodeBuild

CB-001: Secrets in plaintext environment variables

Severity: CRITICAL

Checks for environment variables whose names match common secret patterns (PASSWORD, TOKEN, API_KEY, etc.) that are stored with type PLAINTEXT. Plaintext values are visible in the AWS console, CloudTrail logs, and build logs to anyone with read access.

Recommended actions - Move secrets to AWS Secrets Manager or SSM Parameter Store (SecureString). - Update the CodeBuild environment variable type to SECRETS_MANAGER or PARAMETER_STORE. - Rotate any credentials that may have been exposed in plaintext.

CB-002: Privileged mode enabled

Severity: HIGH

Checks whether the CodeBuild project runs with Docker privileged mode enabled. Privileged mode grants the build container root-level access to the Docker daemon on the underlying host, which is required for Docker-in-Docker builds but significantly increases the blast radius of a compromised build.

Recommended actions - Disable privileged mode unless the project explicitly requires Docker-in-Docker builds. - If privileged mode is required, ensure the buildspec is peer-reviewed and sourced from a protected branch. - Consider using Kaniko or AWS CodeBuild's native Docker layer caching instead of DinD.

CB-003: Build logging not enabled

Severity: MEDIUM

Checks whether the CodeBuild project sends build output logs to CloudWatch Logs or S3. Without logs, build activity cannot be audited, security incidents cannot be investigated, and anomalous build behavior goes undetected.

Recommended actions - Enable CloudWatch Logs in the project's logsConfig.cloudWatchLogs setting. - Alternatively, enable S3 logging to a protected bucket with restricted write access. - Set a log retention period appropriate for your compliance requirements.

CB-004: No build timeout configured

Severity: LOW

Checks whether the CodeBuild project has a build timeout below the AWS maximum of 480 minutes. Projects left at the default ceiling allow runaway or abused builds to consume resources and delay detection of a compromised pipeline stage.

Recommended actions - Set a build timeout appropriate for your expected build duration (typically 15–60 minutes). - Use build phase reports and CloudWatch alarms to alert on builds that approach their timeout.

CB-005: Outdated managed build image

Severity: MEDIUM

Checks whether projects using the AWS-managed CodeBuild standard image are on the latest major version. Older managed images may contain unpatched OS packages, runtimes, or build tools that introduce supply-chain risk into every artifact produced by the pipeline.

Recommended actions - Update the environment image to the latest aws/codebuild/standard:X.0 version. - Pin custom or third-party images to a specific digest rather than a mutable tag. - Subscribe to AWS CodeBuild release notifications to stay informed of new image versions.

CB-006: Source auth uses long-lived token

Severity: HIGH

Checks whether a CodeBuild project with an external source (GitHub, GitHub Enterprise, Bitbucket) authenticates using a long-lived OAuth or personal access token rather than an AWS CodeConnections (CodeStar) connection. The check inspects both the project's inline source.auth.type and the account-level credentials returned by codebuild:ListSourceCredentials, flagging stored OAUTH, PERSONAL_ACCESS_TOKEN, or BASIC_AUTH entries for any server type the project uses.

Recommended actions - Replace OAuth/PAT tokens with a CodeConnections (CodeStar) connection and reference it from the project source. - Delete stored source credentials of type OAUTH, PERSONAL_ACCESS_TOKEN, or BASIC_AUTH via codebuild:DeleteSourceCredentials. - Rotate any exposed tokens and revoke them in the upstream VCS.

CB-007: CodeBuild webhook has no filter group

Severity: MEDIUM

Checks whether a CodeBuild webhook defines at least one filter group. A webhook without filter groups triggers a build on any push from any principal, including pull requests from forks of public repositories, enabling poisoned-pipeline execution.

Recommended actions - Define filter groups that restrict triggers to specific branches and event types. - Add an ACTOR_ACCOUNT_ID filter to block fork-originated builds for public repositories. - Scope HEAD_REF filters to trusted branches (main/release/*) only.


CodePipeline

CP-001: No approval action before deploy stages

Severity: HIGH

Checks whether every Deploy stage in the pipeline is preceded by at least one Manual approval action. Without an approval gate, any code change can reach production automatically with no human review, violating flow control principles.

Recommended actions - Add a Manual approval action to a stage that precedes every Deploy stage targeting production. - Integrate approval notifications with your team's communication tool (e.g. Slack, email). - Consider using AWS CodePipeline approval rules for automated quality gates in addition to manual reviews.

CP-002: Artifact store not encrypted with customer-managed KMS key

Severity: MEDIUM

Checks whether the pipeline artifact store (S3 bucket) uses a customer-managed KMS key rather than the default AWS-managed key (SSE-S3). Default encryption reduces auditability and control over who can decrypt pipeline artifacts.

Recommended actions - Create a customer-managed KMS key and assign it as the encryptionKey in each artifact store configuration. - Apply a key policy that restricts decrypt access to only the pipeline execution role. - Enable CloudTrail logging of KMS API calls to audit all artifact decryption events.

CP-003: Source stage using polling instead of event-driven trigger

Severity: LOW

Checks whether any Source action has PollForSourceChanges=true, meaning the pipeline polls for changes rather than being triggered by an event. Polling increases API quota consumption, introduces latency, and may miss rapid successive changes.

Recommended actions - Set PollForSourceChanges=false on all Source actions. - Configure an Amazon EventBridge rule or CodeCommit trigger to start the pipeline on change. - For GitHub sources, use a CodeStar connection with webhook-based triggering.

CP-004: Legacy ThirdParty/GitHub source action (OAuth token)

Severity: HIGH

Flags Source actions using the deprecated owner=ThirdParty, provider=GitHub configuration. This path authenticates via a long-lived OAuth token stored in the pipeline definition, which cannot be rotated automatically and is visible to anyone with codepipeline:GetPipeline.

Recommended actions - Migrate to owner=AWS, provider=CodeStarSourceConnection with a CodeConnections ARN. - Revoke the legacy OAuth token once migration is complete. - Audit git history for any leaked OAuth tokens committed alongside old pipeline definitions.


CodeDeploy

CD-001: Automatic rollback on failure not enabled

Severity: MEDIUM

Checks whether the CodeDeploy deployment group has autoRollbackConfiguration enabled with the DEPLOYMENT_FAILURE event. Without automatic rollback, a failed deployment leaves the environment in an inconsistent or partially-deployed state until a developer manually intervenes.

Recommended actions - Enable autoRollbackConfiguration on the deployment group with at least the DEPLOYMENT_FAILURE event. - Consider also adding DEPLOYMENT_STOP_ON_ALARM to roll back when health metrics degrade. - Test rollback behavior in a non-production environment to validate the configuration.

CD-002: AllAtOnce deployment config, no canary or rolling strategy

Severity: HIGH

Checks whether the deployment group uses an AllAtOnce configuration (CodeDeployDefault.AllAtOnce, LambdaAllAtOnce, or ECSAllAtOnce). This strategy routes 100% of traffic to the new revision simultaneously, meaning a defective build immediately impacts all users with no canary validation window.

Recommended actions - Switch to a canary deployment configuration (e.g. CodeDeployDefault.LambdaCanary10Percent5Minutes). - For EC2/on-premises workloads, use a rolling or half-at-a-time deployment config. - Pair the graduated deployment with CloudWatch alarms to trigger automatic rollback on error spikes.

CD-003: No CloudWatch alarm monitoring on deployment group

Severity: MEDIUM

Checks whether the CodeDeploy deployment group has at least one CloudWatch alarm configured in its alarmConfiguration. Without alarm-based monitoring, error rate spikes or latency regressions introduced by a deployment will not automatically halt or roll back the release.

Recommended actions - Add CloudWatch alarms covering error rate, 5xx response count, or latency p99 to the deployment group. - Enable alarmConfiguration.enabled and set ignoreAlarmMembershipErrors to false. - Combine with auto-rollback on DEPLOYMENT_STOP_ON_ALARM to create a self-healing deployment pipeline.


ECR

ECR-001: Image scanning on push not enabled

Severity: HIGH

Checks whether the ECR repository has imageScanningConfiguration.scanOnPush enabled. Without scan-on-push, vulnerabilities in base images or dependencies are not detected at push time, allowing unvetted images to propagate through the pipeline and into production.

Recommended actions - Enable imageScanningConfiguration.scanOnPush on the repository. - Consider enabling Amazon Inspector continuous scanning for ongoing CVE detection against images already in the registry. - Integrate scan results into your CI/CD pipeline and fail builds on HIGH or CRITICAL findings.

ECR-002: Image tags are mutable

Severity: HIGH

Checks whether the repository has imageTagMutability set to IMMUTABLE. With mutable tags, any principal with ecr:PutImage can silently overwrite an existing tag (e.g. :latest or a semver tag), allowing a malicious or accidental image swap to affect all deployments that pull by tag without verifying a digest.

Recommended actions - Set imageTagMutability=IMMUTABLE on the repository. - Reference container images by digest (sha256:...) in deployment manifests for the strongest immutability guarantees. - Enforce digest-pinning in your container admission controller or policy engine.

ECR-003: Repository policy allows public access

Severity: CRITICAL

Checks whether the repository resource-based policy contains any Allow statement with a wildcard principal (Principal: '*'). Such statements expose the repository to unauthenticated or cross-account access, potentially allowing unauthorised image pulls or pushes.

Recommended actions - Remove wildcard principals from the repository policy. - Grant pull access only to specific AWS account IDs or IAM principals that require it. - If cross-account access is needed, use explicit account principal ARNs with the minimum necessary actions.

ECR-004: No lifecycle policy configured

Severity: LOW

Checks whether the ECR repository has a lifecycle policy defined. Without automated image cleanup, old and potentially vulnerable images accumulate indefinitely, increasing storage costs and the attack surface for anyone able to pull older tagged images.

Recommended actions - Add a lifecycle policy that expires untagged images after a short period (e.g. 7 days). - Limit the number of tagged image versions retained (e.g. keep the last 10 tagged images). - Test the lifecycle policy in a non-production repository before applying it to critical repos.

ECR-005: Repository encrypted with AES256 rather than KMS CMK

Severity: MEDIUM

Checks whether the repository uses encryptionType=KMS with a customer-managed key. The default AES256 option uses an AWS-managed key that cannot be audited via key policy, rotated on a custom schedule, or restricted per-principal.

Recommended actions - Set encryptionConfiguration.encryptionType=KMS with a customer-managed CMK ARN. - Apply a restrictive key policy limiting decrypt to the pipeline execution role. - Enable CloudTrail logging of KMS calls for audit of every image pull that decrypts layers.


IAM

IAM-001: CI/CD role has AdministratorAccess policy attached

Severity: CRITICAL

Checks whether any IAM role with a CI/CD service trust (CodeBuild, CodePipeline, or CodeDeploy) has the AWS-managed AdministratorAccess policy attached. This grants unrestricted access to all AWS services and resources; a compromised pipeline can perform any action in the account.

Recommended actions - Replace AdministratorAccess with least-privilege policies scoped to the specific actions the role requires. - Use IAM Access Analyzer to identify and remove unused permissions. - Apply Service Control Policies (SCPs) at the AWS Organizations level to further constrain CI/CD role capabilities.

IAM-002: CI/CD role has wildcard Action in attached policy

Severity: HIGH

Checks every reachable policy on a CI/CD service role, inline policies and the default version of attached customer-managed policies, for an Allow statement with Action: '*'. Wildcard actions grant unrestricted access to one or more AWS services, violating least-privilege and widening the blast radius of a compromised build or deployment. AWS-managed policies are intentionally skipped here; IAM-001 handles AdministratorAccess separately.

Recommended actions - Replace wildcard actions with the specific IAM actions the role actually requires. - Use CloudTrail last-access data and IAM Access Analyzer to identify the minimal required action set. - Periodically review and tighten inline policies as pipeline requirements evolve.

IAM-003: CI/CD role has no permission boundary

Severity: MEDIUM

Checks whether CI/CD service roles have a permissions boundary attached. Without a boundary, the role's effective permissions are limited only by its attached policies, and there is no guardrail preventing privilege escalation if a policy is accidentally over-permissioned or modified by an attacker.

Recommended actions - Attach a permissions boundary to each CI/CD service role defining the maximum permissions it can ever be granted. - Create a managed boundary policy that excludes sensitive actions (e.g. iam:CreateRole, iam:AttachRolePolicy without conditions). - Enforce boundary attachment through an SCP or IAM condition on role creation.

IAM-004: CI/CD role can PassRole to any role

Severity: HIGH

Checks whether any policy attached to the CI/CD role grants iam:PassRole (or iam:* or *) with Resource: '*'. A build that can pass any role to a service can escalate into every role the account trusts, which is a classic CI/CD privilege-escalation path.

Recommended actions - Restrict iam:PassRole to the specific role ARNs the pipeline must hand off to. - Add a Condition with iam:PassedToService restricting the destination service. - Use IAM Access Analyzer to confirm the policy surface after tightening.

IAM-005: CI/CD role trust policy missing sts:ExternalId

Severity: HIGH

Checks whether the role's trust policy allows assumption by an AWS account principal without an sts:ExternalId condition. External-account trust without an ExternalId is the classic confused-deputy pattern described in the IAM Best Practices.

Recommended actions - Add a Condition requiring sts:ExternalId for every external-principal statement. - Prefer service-linked principals over AWS account principals wherever possible. - Rotate ExternalIds on a regular schedule and treat them as secrets.

IAM-006: Sensitive actions granted with wildcard Resource

Severity: MEDIUM

Flags Allow statements that scope Action (not to '*') but leave Resource as '*' for sensitive services, s3, kms, secretsmanager, ssm, iam, sts, dynamodb, lambda, ec2. IAM-002 catches Action:'*'; this check catches the more common "scoped action, unscoped resource" pattern that evades it.

Recommended actions - Constrain Resource to specific ARNs (bucket/*, key ARN, secret ARN, role ARN). - Where wildcards are unavoidable (e.g. ec2:Describe*), isolate those statements from write actions. - Use IAM Access Analyzer last-access data to produce tighter policies automatically.


PBAC (Pipeline-Based Access Control)

PBAC checks target the boundary between the pipeline itself and the resources it can reach, network reachability and service-role sharing across projects.

PBAC-001: CodeBuild project has no VPC configuration

Severity: HIGH

Checks whether a CodeBuild project runs with an attached vpcConfig block. Without VPC isolation the build container executes on a shared AWS-managed network with unrestricted egress, so a compromised build can exfiltrate secrets or artifacts to any destination on the public internet.

Recommended actions - Attach vpcConfig pointing the project at a private subnet with an egress-controlled security group. - Route required traffic through VPC endpoints (S3, ECR, Secrets Manager, CloudWatch Logs) instead of public internet. - Deny 0.0.0.0/0 egress on the build security group unless strictly required.

PBAC-002: CodeBuild service role shared across projects

Severity: MEDIUM

Checks whether multiple CodeBuild projects reuse the same serviceRole. A shared role means any single project's compromise grants the attacker the combined permissions of every project that uses the role, the exact cross-pipeline escalation path PBAC is meant to prevent.

Recommended actions - Give each CodeBuild project its own dedicated service role scoped to only the secrets, buckets, and ECR repos that project needs. - If role duplication is unavoidable, group only projects with identical trust boundaries. - Detect new shared-role situations with an AWS Config rule or a recurring scan via this tool.


S3

S3-001: Artifact bucket public access block not fully enabled

Severity: CRITICAL

Checks whether all four S3 Block Public Access settings are enabled on CodePipeline artifact buckets: BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, and RestrictPublicBuckets. Missing settings could expose pipeline artifacts if a bucket ACL or policy is accidentally permissive.

Recommended actions - Enable all four Block Public Access settings on every artifact bucket. - Apply the same settings at the AWS account level as a catch-all default. - Use AWS Config rule s3-bucket-public-read-prohibited to continuously audit public access.

S3-002: Artifact bucket server-side encryption not configured

Severity: HIGH

Checks whether the CodePipeline artifact bucket has a default server-side encryption rule configured. Without encryption at rest, pipeline artifacts (source zips, compiled binaries, deployment packages) are stored unencrypted, increasing exposure if S3 access controls are misconfigured.

Recommended actions - Enable default bucket encryption using at minimum AES256 (SSE-S3). - For stronger key control, use SSE-KMS with a customer-managed key. - Enforce encryption-in-transit by adding a bucket policy that denies requests without aws:SecureTransport.

S3-003: Artifact bucket versioning not enabled

Severity: MEDIUM

Checks whether versioning is enabled on the CodePipeline artifact bucket. Without versioning, overwritten or deleted artifacts cannot be recovered, making it impossible to roll back to a known-good build artifact after an incident or accidental overwrite.

Recommended actions - Enable S3 versioning on every artifact bucket. - Pair versioning with a lifecycle rule that expires non-current versions after your retention period. - Consider enabling MFA Delete for additional protection against accidental or malicious deletion.

S3-004: Artifact bucket access logging not enabled

Severity: LOW

Checks whether S3 server access logging is enabled on CodePipeline artifact buckets. Without access logs it is not possible to audit who accessed, downloaded, or tampered with pipeline artifacts during an investigation.

Recommended actions - Enable S3 server access logging and direct logs to a separate, centralized logging bucket. - Restrict write access to the logging bucket so log entries cannot be tampered with. - Use Amazon Athena or CloudWatch Logs Insights to query access logs for anomalous patterns.

S3-005: Artifact bucket missing aws:SecureTransport deny

Severity: MEDIUM

Checks whether the artifact bucket has a bucket policy that denies s3:* when aws:SecureTransport is false. Without this deny, plaintext HTTP requests to the bucket succeed, allowing artifact contents to traverse the network unencrypted.

Recommended actions - Attach a bucket policy with a Deny statement for s3:* where Bool aws:SecureTransport=false. - Apply the deny at the AWS account level via an SCP for defense-in-depth. - Validate the policy with AWS Access Analyzer before applying to production buckets.


Rule-based checks (Phase 1-3)

Every check below is one module under pipeline_check/core/checks/aws/rules/<id>_<slug>.py. Each exports a RULE (metadata) and a check(catalog) callable. Full description, recommendation, and prose live in the rule module itself; the orchestrator (AWSRuleChecks in aws/workflows.py) loads every rule and passes a shared ResourceCatalog.

CodeBuild (CB-008..010)

ID Severity OWASP Description
CB-008 HIGH CICD-SEC-4 Buildspec declared inline / from S3 rather than repo-sourced
CB-009 MEDIUM CICD-SEC-3 Custom CodeBuild image not pinned by @sha256: digest
CB-010 HIGH CICD-SEC-4 Webhook accepts PR events without an ACTOR_ACCOUNT_ID filter

CloudTrail (CT-001..003)

ID Severity OWASP Description
CT-001 HIGH CICD-SEC-10 No actively-logging trail in the region
CT-002 MEDIUM CICD-SEC-10 Trail has LogFileValidationEnabled = false
CT-003 MEDIUM CICD-SEC-10 Trail is region-scoped (not multi-region)

CloudWatch Logs (CWL-001, 002)

ID Severity OWASP Description
CWL-001 LOW CICD-SEC-10 /aws/codebuild/* log group has no retention policy
CWL-002 MEDIUM CICD-SEC-9 /aws/codebuild/* log group not KMS-CMK encrypted

Secrets Manager (SM-001, 002)

ID Severity OWASP Description
SM-001 HIGH CICD-SEC-6 Secret referenced by CodeBuild has no rotation configured
SM-002 CRITICAL CICD-SEC-8 Resource policy grants Principal: "*"

IAM (IAM-007, 008)

ID Severity OWASP Description
IAM-007 HIGH CICD-SEC-6 User access key older than 90 days
IAM-008 HIGH CICD-SEC-2 OIDC-federated role trust policy lacks :aud or :sub pin

CodeArtifact (CA-001..004)

ID Severity OWASP Description
CA-001 MEDIUM CICD-SEC-9 Domain not encrypted with a customer-managed CMK
CA-002 HIGH CICD-SEC-3 Repository has direct public:* external connection
CA-003 CRITICAL CICD-SEC-8 Domain permissions policy allows cross-account wildcard
CA-004 HIGH CICD-SEC-2 Repo policy grants codeartifact:* with Resource *

CodeCommit (CCM-001..003)

ID Severity OWASP Description
CCM-001 HIGH CICD-SEC-1 No approval-rule template attached to the repo
CCM-002 MEDIUM CICD-SEC-9 Repo not encrypted with a customer-managed CMK
CCM-003 MEDIUM CICD-SEC-8 Trigger destination is in a different AWS account

Lambda (LMB-001..004)

ID Severity OWASP Description
LMB-001 HIGH CICD-SEC-9 Function has no CodeSigningConfigArn
LMB-002 HIGH CICD-SEC-8 Function URL configured with AuthType = NONE
LMB-003 HIGH CICD-SEC-6 Env vars contain secret-like plaintext values
LMB-004 CRITICAL CICD-SEC-8 Resource policy grants Principal: "*" without scope

KMS (KMS-001, 002)

ID Severity OWASP Description
KMS-001 MEDIUM CICD-SEC-6 Customer-managed symmetric key has rotation disabled
KMS-002 HIGH CICD-SEC-2 Key policy grants kms:* to an IAM principal

SSM Parameter Store (SSM-001, 002)

ID Severity OWASP Description
SSM-001 HIGH CICD-SEC-6 Parameter with secret-like name stored as String, not SecureString
SSM-002 MEDIUM CICD-SEC-9 SecureString uses alias/aws/ssm rather than a CMK

Phase-3 deeper detections

ID Severity OWASP Description
ECR-006 HIGH CICD-SEC-3 Pull-through cache rule has an unauthenticated untrusted upstream
ECR-007 MEDIUM CICD-SEC-3 Inspector v2 enhanced scanning for ECR is disabled
SIGN-001 MEDIUM CICD-SEC-9 No active AWS Signer profile exists for the Lambda platform
SIGN-002 HIGH CICD-SEC-9 Signer profile is revoked or canceled
EB-001 MEDIUM CICD-SEC-10 No EventBridge rule for CodePipeline ... FAILED events
EB-002 HIGH CICD-SEC-8 EventBridge rule has a wildcard target ARN
CW-001 LOW CICD-SEC-10 No CloudWatch alarm on AWS/CodeBuild FailedBuilds
PBAC-003 MEDIUM CICD-SEC-5 CodeBuild security group allows 0.0.0.0/0 all-port egress
PBAC-005 HIGH CICD-SEC-5 Pipeline action roles all equal the pipeline-level role
CP-005 MEDIUM CICD-SEC-1 Production-named stage has no preceding ManualApproval
CP-007 HIGH CICD-SEC-4 V2 pipeline PR trigger has no branches.includes filter

Degraded findings. When the caller's IAM principal can't list resources for a service, the orchestrator emits one <PREFIX>-000 finding (INFO severity) per failed service, CT-000, CA-000, LMB-000, etc., instead of every dependent rule emitting its own error copy.


Adding a new AWS check

Rule-based (preferred)

  1. Drop a single module in pipeline_check/core/checks/aws/rules/<id>_<slug>.py exporting a RULE (metadata) and a check(catalog) callable. The orchestrator and this doc's table pick it up automatically.
  2. If the check needs a new enumeration, add a cached method to ResourceCatalog in pipeline_check/core/checks/aws/_catalog.py.
  3. Add the check ID to pipeline_check/core/standards/data/owasp_cicd_top_10.py (and any other relevant standards).
  4. Add unit tests in tests/aws/rules/test_<name>.py using the make_catalog fixture.
  5. (Recommended) Add a Terraform parity rule in pipeline_check/core/checks/terraform/{extended,services,phase3}.py so shift-left scans stay at parity with runtime.

Class-based (legacy, for large new service modules)

  1. Create pipeline_check/core/checks/aws/<service>.py subclassing AWSBaseCheck. Use self.client("<svc>") (retry-configured, cached).
  2. Import it and append to check_classes in pipeline_check/core/providers/aws.py.
  3. Add unit tests in tests/aws/test_<service>.py.
  4. Add mappings for the new check IDs in the relevant standard file(s) under pipeline_check/core/standards/data/.
  5. Extend the corresponding service section in this document with the new check entry (title, severity, description, recommended actions).