CertNote/ Commute Study Notes
Roadmap
KOEN
CLF-C02 · FoundationalCloud Practitioner - Foundational
DVA-C02 · AssociateDeveloper - Associate
SAA-C03 · AssociateSolutions Architect - Associate
SOA-C02 · AssociateCloudOps Engineer - Associate
SAP-C02 · ProfessionalSolutions Architect - Professional
DOP-C02 · ProfessionalDevOps Engineer - Professional
  • Week 1
    • 1.DevOps as an Operating Model: The Five Axes of CALMS and the Truth DORA Proved Through Measurement
    • 2.Well-Architected Framework: Rereading It Through the Six Lenses of DevOps
    • 3.The AWS DevOps Tool Map: The Code* Series and the Real Picture Beyond It
    • 4.Multi-Account Strategy: The Real Picture of Organizations, Control Tower, and IAM Identity Center
    • 5.Week 1 Wrap-Up: Cementing the DevOps Thinking Frame with Scenarios
  • Week 2
    • 1.CodeCommit Deep Dive: What Changes When Git Hosting is Integrated with IAM
    • 2.GitHub Actions ↔ AWS OIDC: Eliminating Static Keys Permanently Through Federation
    • 3.CodeArtifact and Supply Chain Security: When Dependencies Become Attack Surface
    • 4.DevSecOps Shift Left: Automated Security Gates Built with Code Signing, CodeGuru, and Inspector
    • 5.Week 2 Wrap-Up: From Source Control to Code Signing, Cementing the DevSecOps Mindset Through Scenarios
  • Week 3
  • Week 4
  • Week 5
  • Week 6
  • Week 7
  • Week 8
  • Week 9
  • Week 10
  • Week 11
  • Week 12
  • Week 13
  • Week 14
  • Week 15
  • Week 16
Linux Master 2 · 2급KAIT Linux Master - Level 2
SCS-C03 · SpecialtySecurity - Specialty
Linux Master 1 · 1급KAIT Linux Master - Level 1
MLA-C01 · AssociateMachine Learning Engineer - Associate
AIF-C01 · FoundationalAI Practitioner - Foundational
DEA-C01 · AssociateData Engineer - Associate
MLS-C01 · SpecialtyMachine Learning - Specialty
SQLD · 개발자SQL Developer (SQLD)

© CertNote · 주간랩스

  • About
  • Changelog
  • Contact
  • Terms
  • Privacy
← DOP-C02/Week 2/Day 3

Based on the DOP-C02 exam guide·Report an error

DOP-C02· ProWeek 2 · Day 3~38 min read

Day 3 - CodeArtifact and Supply Chain Security: When Dependencies Become Attack Surface

December 2020: SolarWinds, December 2021: Log4Shell, 2022: ua-parser-js malware injection, 2023: PyTorch nightly dependency confusion attack—what do the largest security incidents of the past five years have in common? All penetrated through the software supply chain. Not direct code exploitation but through dependent packages.

As this landscape shifts, "where you get packages from" becomes a first-class security concern in CI/CD systems. CodeArtifact is AWS's answer. On the surface it's a "managed npm/Maven/PyPI mirror", but in reality it means creating a single entry point for supply chain that enables a controllable trust boundary.

Today covers: ① why CodeArtifact's Domain/Repository layering is designed that way ② how Upstream chaining absorbs external registry failures and package unpublishes ③ how Dependency Confusion attacks work and how CodeArtifact's namespace prevents them ④ the three-layer permission evaluation (IAM + Repository Policy + Domain Policy) ⑤ where emerging standards like SBOM/SLSA/Sigstore fit in.

Real-World Supply Chain Attacks — Why Using External Registries Directly Is Dangerous

To understand CodeArtifact's value, you must first see "why is using external registries directly risky?" Let me review actual incidents.

YearIncidentMechanismImpact
2016left-pad unpublishAuthor deletes package from npm → React/Babel builds halt entirelyHalf the internet's build systems paralyzed. An 11-line function caused havoc
2018event-stream hijack after takeoverPopular package permissions transferred to malicious developer → Bitcoin wallet theft code injected2 million downloads/week
2020SolarWinds OrionBuild system infiltrated → backdoor inserted into officially signed updates18,000 US government organizations affected
2021Log4Shell (Log4j 2.x JNDI)RCE through Log4j lookup functionApache ecosystem system-wide, government/enterprise emergency
2021Codecov bash uploaderCredential extraction code injected into build scriptHashiCorp, Twilio and others affected
2021ua-parser-js account hijackOfficial maintainer account compromised → malware added7 million downloads/week at time of discovery
2022colors.js sabotageAuthor added infinite loop code to his own packageNode.js ecosystem disrupted
2023PyTorch nightly dependency confusionDummy package torchtriton published to PyPI → PyTorch build chose PyPI over internalPyTorch nightly users' credentials leaked
2024xz-utils backdoor (CVE-2024-3094)2-year social engineering gained maintainer access, SSH backdoor insertedsystemd dependency → nearly all Linux distros at risk before discovery

This list isn't random incidents. Build systems directly depending on external registries immediately absorb external incidents—cumulative evidence. Without an intermediate cache and control layer like CodeArtifact, all the incidents above would have entered builds at build time.

📚 Case Detail: The 2016 left-pad incident started with a single line decision (author ran npm unpublish). When npm sided against him in a Kik Messenger package naming dispute, he unpublished all his packages. left-pad was transitively depended on by React, Babel, Webpack, and others; consequently, builds worldwide broke simultaneously. After this incident, npm introduced a 24-hour unpublish window, and many organizations began implementing internal mirrors. CodeArtifact's Upstream cache principle exactly embodies the lesson from this incident.

Domain and Repository Layers — Why Two Levels?

CodeArtifact isn't a single plane but a Domain → Repository two-tier hierarchy. This separation is intentional and frequent on exams.

Domain (organizational unit, usually 1-2)
├── KMS Key (encrypt all Domain assets)
├── Asset Storage (deduplication)
├── Domain Policy (broad permissions)
│
├── Repository: production
│   ├── Repository Policy
│   ├── Upstream → shared-cache
│   └── Packages: app-frontend@1.2.3, app-backend@2.0.1, ...
│
├── Repository: development
│   ├── Repository Policy
│   ├── Upstream → shared-cache
│   └── Packages: ...
│
└── Repository: shared-cache
    ├── External Connection → public:npmjs, public:pypi
    └── Packages: lodash@4.17.21, requests@2.28.0, ...
UnitDesign Meaning
DomainUnified asset storage + single KMS key. Even if same lodash@4.17.21 exists in multiple Repositories, Domain stores it once. Unit for billing.
RepositoryUnit for permissions, Upstream, external connections. One Domain can have dozens to hundreds of Repositories.

🔍 Deep Dive: Domain's KMS key unification is subtle but important. Adding more Repositories within the same Domain needs no new KMS key. However, moving data between Domains involves different KMS keys, requiring separate decrypt-encrypt cost. So organizations typically keep Domains small (1-2) and separate environments by Repository. In exams, when "why not create more Domains?", the answer is almost always asset deduplication + KMS unity.

💡 Related Theory: This two-tier model is an instance of multi-tenancy in storage pattern—providing isolated views on shared storage. AWS S3 with multiple prefixes in one bucket, Kubernetes with namespaces in one cluster follow the same philosophy. Shared infrastructure (storage) stays singular; logical isolation (permissions, views) handled at higher layers.

Upstream and External Connection — The Value of a Single Entry Point

CodeArtifact's most powerful feature is Upstream chaining. Connecting Upstream to a Repository automatically fetches and caches packages not found locally.

Build tool (npm install lodash@4.17.21)
    |
    | npm config registry = https://...codeartifact.ap-northeast-2.amazonaws.com/npm/production/
    v
[CodeArtifact: production]
    | cache miss
    v
[CodeArtifact: shared-cache]
    | cache miss
    v
[External Connection: public:npmjs]
    v
npmjs.com
    | download
    v
store in shared-cache
view from production (assets stored once in Domain)
    v
deliver to build

This structure's value has multiple layers:

ValueMechanism
External Outage Isolationnpmjs.com down? Cached packages still serve normally
Deletion ProtectionEven if unpublished externally, cache copy remains (prevents left-pad incident)
Supply Chain ControlAll external packages pass through shared-cache single entry point → blocking policy, audit, scanning entry
Cost ReductionPrevent repeated downloads of identical packages
SpeedWithin-region cache hit = millisecond response

⚠️ Trap: External Connection should only connect to leaf Repositories like shared-cache, not directly to production Repository. Direct External Connection to production bypasses blocking policy. In exams, "standard CodeArtifact for supply chain control" almost always shows "production → shared → external" 3-tier.

🔍 Deep Dive: External Connections can attach to public:npmjs, public:maven-central, public:maven-googleandroid, public:maven-clojars, public:maven-commonsware, public:pypi, public:nuget-org, public:ruby-gems-org, etc. One per Repository, one External Connection handles one package format. Multi-language builds split format by Repository.

📚 Case Study: A payments company updated all internal builds to Log4j 2.17.1 within 4 hours during December 2021's Log4Shell crisis. The secret: adding a blocking policy to CodeArtifact's shared-cache Repository—"Log4j 2.0-2.16 packages deny ReadFromRepository". Builds automatically requested new versions; all environments upgraded consistently. Without CodeArtifact, this control was impossible with external npm/Maven directly.

Three Permission Layers — IAM + Repository Policy + Domain Policy Evaluation Order

CodeArtifact controls permissions with three policy layers. This is where exams confuse students.

LayerDefined AtScopeAnalogy
IAM Identity PolicyUser/RoleWhat actions that Principal can take"What I can do"
Repository PolicyRepository itselfWho can access that Repository (cross-account included)"Who can enter this Repository"
Domain PolicyDomain itselfBroad impact on all assets/Repositories within Domain"Rules applying to entire Domain"

Evaluation order:

1. Domain Policy evaluation (broad deny first)
   └→ explicit Deny → immediate rejection
2. Repository Policy evaluation
   └→ explicit Deny → immediate rejection
3. IAM Identity Policy evaluation
   └→ explicit Allow required

cross-account requires Allow on both sides (Identity + Resource)

⚠️ Trap: If Repository Policy grants read to another account's Role but Domain Policy blocks that Org, the result is denial. Domain Policy evaluates first at broad level. In exams, "Repository Policy allows cross-account but fails" scenario's answer is almost always Domain Policy or KMS key policy.

// Domain Policy example — only specific Org allowed
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": "*",
    "Action": ["codeartifact:GetAuthorizationToken"],
    "Resource": "*",
    "Condition": {
      "StringEquals": {
        "aws:PrincipalOrgID": "o-abc123"
      }
    }
  }]
}
// Repository Policy — only CI bot publishes, all workers read
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublishOnlyByCi",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111:role/CodeBuildRole"
      },
      "Action": ["codeartifact:PublishPackageVersion", "codeartifact:WriteFromRepository"],
      "Resource": "*"
    },
    {
      "Sid": "ReadByAllWorkers",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": ["codeartifact:ReadFromRepository", "codeartifact:GetPackageVersionAsset"],
      "Resource": "*",
      "Condition": {
        "StringEquals": { "aws:PrincipalOrgID": "o-abc123" }
      }
    }
  ]
}

💡 Related Theory: AWS's policy evaluation model follows deny-by-default + explicit Allow + explicit Deny is highest priority—a consistent rule. When Domain Policy + Repository Policy + IAM Identity Policy + KMS Key Policy + SCP all cross-cut, debugging is hard. AWS IAM Policy Simulator or CloudTrail's errorCode reveals which layer denied.

Dependency Confusion — The Attack CodeArtifact Specifically Prevents

Dependency Confusion is an attack documented in 2021 by Alex Birsan, demonstrated against Microsoft, Apple, PayPal and 34 other companies. Mechanism:

[Attack scenario]
1. Company publishes @company/internal-utils@1.0.0 to internal npm
2. Attacker publishes identical-name internal-utils@99.99.99 to npmjs.com (no namespace)
3. Company build calls npm install internal-utils
4. npm searches both → chooses higher version (99.99.99)
5. Attacker code enters company build

Two defenses exist:

DefenseMechanism
Scoped namespaceUse @company/internal-utils organization scope. npmjs.com can't publish same scope (npm blocks)
Single entry point + lock fileForce CodeArtifact production as unique npm registry. Commit lock file (package-lock.json) to git for exact hash pinning

🔍 Deep Dive: Lock files matter not just for version pinning but because they include integrity hash. The integrity: "sha512-..." field in package-lock.json is the package's exact content hash. If package changes in transit, hash mismatch rejects it. yarn's yarn.lock, pip's --require-hashes work on same principle.

📚 Case Study: Alex Birsan demonstrated successful code execution on 35 companies via dependency confusion within one month, receiving $1.3M bug bounty. Shocking that even largest firms didn't enforce lock files or use scoped names. In exams, when "Dependency Confusion defense" appears, the answer is always ① scoped namespace ② single registry (CodeArtifact) ③ lock file—all three.

Authentication Token — 12-Hour Lifetime Meaning and Automation Pattern

CodeArtifact issues 12-hour authentication tokens in a model similar to STS. You inject this token into .npmrc, pip.conf, ~/.m2/settings.xml for build tools to use.

# Standard all-in-one pattern
aws codeartifact login --tool npm \
  --repository production \
  --domain my-org \
  --domain-owner 111111111111 \
  --region ap-northeast-2
 
# Internally:
# 1. get-authorization-token called (valid 12 hours)
# 2. ~/.npmrc updated
#    registry=https://my-org-111111111111.d.codeartifact.ap-northeast-2.amazonaws.com/npm/production/
#    //my-org-111111111111.d.codeartifact.ap-northeast-2.amazonaws.com/:_authToken=<token>
# 3. always-auth=true set

🔍 Deep Dive: 12 hours is no accident. 99% of CI/CD builds finish within 1 hour, but overnight large builds or multi-stage release pipelines run 4-8 hours. 12 hours covers all cases while limiting token leak impact. In exams, "token lifetime" answer is always 12 hours.

⚠️ Trap: What if token expires mid-build? Token is valid from issue time, not build start. So refresh token right before build is standard. CodeBuild's pre_build phase, GitHub Actions' first step always retrieves fresh.

SBOM, SLSA, Sigstore — Emerging Standards for Supply Chain Security

CodeArtifact stores packages; determining "are these packages really safe?" is separate tools' job.

StandardMeaningAWS Integration
SBOM (Software Bill of Materials)Software component list. SPDX, CycloneDX formatsInspector can auto-generate for EC2/ECR
SLSA (Supply-chain Levels for Software Artifacts)Google-led supply chain integrity grading (Levels 1-4)CodeBuild + CodePipeline + Sigstore achieves SLSA L3
Sigstore (cosign, fulcio, rekor)OIDC-based code signing, keyless signingECR + cosign for container signing
in-totoBuild-phase integrity attestationFoundation of SLSA framework

💡 Related Theory: SLSA Framework (2021) is a direct response to SolarWinds incident. Google standardized how its Borg build system guarantees build integrity. Level 1 (build script documentation) → Level 2 (verified provenance) → Level 3 (source/build isolation, tamper-resistant) → Level 4 (2-reviewer + reproducible build). When exam asks "how ensure supply chain integrity", SLSA appearing as choice is almost the answer.

📚 Case Study: 2023, a SaaS company achieving SLSA L3 by ① building all container images only in CodeBuild + signing with cosign in ECR ② auto-generating SBOM per build stored to S3 ③ verifying signature with cosign before CodeDeploy, blocking on failure. Six months later when npm dependency was hijacked, SBOM diff immediately revealed impact scope.

CodeArtifact vs S3 vs ECR — What Goes Where

Use CaseAppropriate ServiceWhy
npm/Maven/PyPI/NuGet/GradleCodeArtifactNative package manager protocol
Container images (Docker, OCI)ECROCI-compliant, integrated image scanning
Helm ChartECR (OCI) or S3Helm 3+ OCI-compatible
General binary, zip build artifactsCodeArtifact Generic or S3Generic for search/versioning, S3 for simple storage
CodePipeline artifact temp storageS3Auto-expire via lifecycle policy
ML model filesS3 or SageMaker Model RegistryLatter for metadata + versioning
Terraform ModuleCodeArtifact Generic or S3Replaces Terraform Cloud private registry

🎯 Scenario: A company wants "50 internal Helm Charts deployed safely". Answer? Not CodeArtifact but ECR (OCI). Helm 3+ is OCI-compatible, so it uses container infrastructure (ECR + cosign signing + scanning). In exams, Helm Chart choice is a trap—looks CodeArtifact but answer is ECR.

⭐ Key Points

  1. ⭐ Domain = asset deduplication + KMS unity. Same package across multiple Repositories stores once.
  2. ⭐ 3-tier Upstream structure (production → shared → external) is standard. Single entry for blocking/audit/scanning.
  3. ⭐ Three-layer permission evaluation: Domain Policy → Repository Policy → IAM Identity Policy. Domain Policy evaluates first.
  4. ⭐ Auth token 12 hours. Refresh via aws codeartifact login right before build.
  5. ⭐ Dependency Confusion defense = scoped namespace + single registry + lock file.
  6. ⭐ Docker/OCI images use ECR, not CodeArtifact. Helm Charts also ECR (OCI) preferred.
  7. ⭐ SLSA, SBOM, Sigstore are emerging standards. CodeBuild + ECR + cosign = SLSA L3 achievable.

📝 Practice Questions

Click a choice to reveal the answer and explanation.

Question 1

What is the most appropriate CodeArtifact configuration to defend against Dependency Confusion attacks?

Question 2

What is the biggest difference between a domain and a repository?

Question 3

What is the maximum lifetime of a CodeArtifact authorization token in CodeBuild?

Question 4

A dependency that was on npmjs.com has been unpublished. What happens to builds that were pulling it through CodeArtifact?

Question 5

How can you ensure that only the build bot can publish packages while developers can only read?

Question 6

Which package format does CodeArtifact not support?

Question 7

Which arguments are required when using CodeArtifact across accounts?

Question 8

You want to respond to a supply chain incident like SolarWinds at the build infrastructure level. What is the most appropriate combination?

Question 9

You allowed read access to another account through a repository policy, but cross-account access fails. What should you suspect first?

Question 10

You want to keep 50 Helm charts in a secure internal repository. Which service is most appropriate?

📌 Today's Summary

The real value of CodeArtifact is not being an "AWS-native npm/Maven mirror" but creating a single entry point to the software supply chain and drawing a controllable trust boundary. The domain handles asset deduplication and a single KMS key, and the repository is the unit for permissions, upstreams, and external connections. The standard structure is three tiers, production → shared → external, forcing all external packages through shared to create a single point for blocking, auditing, and scanning. The answer for Dependency Confusion defense is the three-part combination of scoped namespace + a single registry + lock files, and SLSA/SBOM/Sigstore are the emerging standards for supply chain integrity. Do not forget that Docker/OCI belongs in ECR, not CodeArtifact. Tomorrow we move on to how these packages are actually injected into the build environment in CodeBuild.

PreviousGitHub Actions ↔ AWS OIDC: Eliminating Static Keys Permanently Through FederationWeek 2 · Day 2Next DevSecOps Shift Left: Automated Security Gates Built with Code Signing, CodeGuru, and InspectorWeek 2 · Day 4

Official references

  • DOP-C02 official exam page(opens in a new tab)
  • Amazon S3 documentation(opens in a new tab)
  • AWS KMS documentation(opens in a new tab)
  • AWS IAM documentation(opens in a new tab)
  • AWS CodeBuild documentation(opens in a new tab)

On this page

  • Real-World Supply Chain Attacks — Why Using External Registries Directly Is Dangerous
  • Domain and Repository Layers — Why Two Levels?
  • Upstream and External Connection — The Value of a Single Entry Point
  • Three Permission Layers — IAM + Repository Policy + Domain Policy Evaluation Order
  • Dependency Confusion — The Attack CodeArtifact Specifically Prevents
  • Authentication Token — 12-Hour Lifetime Meaning and Automation Pattern
  • SBOM, SLSA, Sigstore — Emerging Standards for Supply Chain Security
  • CodeArtifact vs S3 vs ECR — What Goes Where
  • Key Points
  • Practice Questions
  • Today's Summary