In the last blog, we were building and deploying inmutable oci packages from the pipeline to AWS EKS cluster uaing a model hub-spoke with argocd, kro y ack managed using KCL librarys in AWS EKS to create resources.
Check last blog
The next step is making it verifiable: signing every artifact, and having the cluster refuse to run anything it can't verify.
With AWS Signer is possible to add additional security layer, the managed service of code signature. Is used in two different moments: inside of pipeline before of render the manifests (we verify that KCL library that is used is signed by an offical profile in AWS signer), and inside EKS Cluster through a PreSync hook of ArgoCD that verify the signature of final artifact just before of applied. In both cases the question is: the signature is the same, no one modified it after signing it?
Note: That an package is signed not means that is secure, only added an step for validate that never changed since was signed.
AWS Signer is the managed service of code signature. signature cryptographically packages of software for validate that in a moment of deploy you canverify two things: that come from a trusted source, and that no one altered them after they were signed.
Prerequisites
Architecture
The signature flow and promotion: push to branch → build → signature of KCL library (
blueprints) verified before of render → render and push of package of manifests → PR of "Pinning the Exact Digest" promotion → humman approval → ArgoCD use the reference → PreSync hook verify the signature of package against that digest before apply.
Check all code in this repository for replicate this blog.
IAC Infraestructure
segoja7 / aws_eks_capabilities_carm
Cross-Account Resource Management
Terraform Terragrunt Scaffold
Enterprise-grade AWS infrastructure scaffold using Terraform and Terragrunt with a layered architecture based on Domain-Driven Design (DDD) principles. Backs the GitOps Beyond Git blog series: a hub-spoke EKS Capabilities platform (ArgoCD, KRO, ACK, managed) delivered via OCI and GitOps, with AWS Signer–verified supply-chain security on top.
- Part 1 — Immutable Platform Delivery with OCI and Argo CD
- Part 2 — AWS Signer in the supply chain (signing, digest pinning, and why signing alone isn't enough) — this repo's
docs/blog-part2-final.md
Architecture
The project implements four infrastructure layers with strict dependency ordering:
Foundation → Platform → Application → Observability It spans two AWS accounts in the same Organization — a hub that owns the EKS cluster, the CI/CD pipeline, and the ArgoCD capability, and a spoke that only trusts the hub's ACK controller to create resources on its behalf (CARM — Cross-Account Resource Management):
accounts/ ├── hub/ # 700922282251…KCL-YAML Kro-ack CRD.
segoja7 / aws-eks-capabilities-kro-ack-argocd-oci-pipeline
OCI and Argo CD using EKS Capabilities (KRO, ACK )
With everything deployed, let see how the pipeline works with additional layer signatures.
The pipeline working
1. triggering the pipeline with the kro-ack-argocd-oci code.
$ git push codecommit main remote: Validating objects: 100% To https://git-codecommit.us-east-1.amazonaws.com/v1/repos/platform-engineering-from-scratch * [new branch] main -> main $ aws codepipeline list-pipeline-executions --pipeline-name base-eks-dev-cicd \ --max-items 1 --query 'pipelineExecutionSummaries[0].[pipelineExecutionId,status]' --output text eb1228da-6955-4214-bf2b-c3540241d812 InProgress 2. The pipeline signature, render, and open a PR
3. Who has permission to approve and merge?
$ aws iam get-role-policy --role-name base-eks-dev-platform-approver \ --policy-name base-eks-dev-platform-approver \ --query 'PolicyDocument.Statement[0].Action' [ "codecommit:UpdatePullRequestApprovalState", "codecommit:MergePullRequestByFastForward", "codecommit:ListPullRequests", "codecommit:GetPullRequestApprovalStates", "codecommit:GetPullRequest", "codecommit:GetDifferences", "codecommit:GetCommit", "codecommit:EvaluatePullRequestApprovalRules" ] These are the entities that can assume the role, approve the PR, and merge it.
$ aws iam get-role --role-name base-eks-dev-platform-approver \ --query 'Role.AssumeRolePolicyDocument' { "Version": "2012-10-17", "Statement": [ { "Sid": "operator", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::<>:root" }, "Action": "sts:AssumeRole", "Condition": { "ArnLike": { "aws:PrincipalArn": "arn:aws:iam::<>:role/aws-reserved/sso.amazonaws.com/*AdministratorAccess*" } } } ] } 4. ArgoCD updates the reference — and the hook triggers.
the merge is exactly the last commit en main the file that argocd read like as source of true change its targetRevision by the new digest.
Argo detect the new change in Git, sincronized the application and the PreSync hook triggers before anything is applied.
segoja7@renderer:~$ kubectl get jobs -n argocd -w NAME STATUS COMPLETIONS DURATION AGE verify-manifests-signature Running 0/1 0s verify-manifests-signature Running 0/1 0s 0s verify-manifests-signature Running 0/1 1s 1s segoja7@renderer:~kubectl logs -n argocd job/verify-manifests-signature -f Trust policy configuration imported successfully. Warning: existing trust policy configuration file will be overwritten layer-1-rgds is pinned to: sha256:40992367b217695f8c516e6a47dea6759772697d52a7b19407203fcc238c27b5 Verifying 700922282251.dkr.ecr.us-east-1.amazonaws.com/kcl-modules/manifests@sha256:40992367b217695f8c516e6a47dea6759772697d52a7b19407203fcc238c27b5 ... Successfully verified signature for 700922282251.dkr.ecr.us-east-1.amazonaws.com/kcl-modules/manifests@sha256:40992367b217695f8c516e6a47dea6759772697d52a7b19407203fcc238c27b5 The hook completed, and PreSync kept its promise: nothing was applied before that. As soon as it finished, ArgoCD proceeded with the actual apply—the ResourceGraphDefinitions that layer-1-rgds exists to register:
$ kubectl get crd | grep kro.run eksclusters.kro.run 2026-10-12T22:01:59Z vpcnetworks.kro.run 2026-10-12T22:02:01Z resourcegraphdefinitions.kro.run 2026-10-12T22:03:01Z $ kubectl get resourcegraphdefinitions.kro.run NAME APIVERSION KIND STATE READY AGE eks-cluster v1alpha1 EKSCluster Active True 1m vpc-network v1alpha1 VPCNetwork Active True 1m One to three seconds after the hook finished, the CRDs were already registered and marked as Active/Ready. With EKSCluster and VPCNetwork available as types in the cluster, the component required for the next step is ready: an actual claim requesting a cluster, built upon the very CRDs we just saw come into existence under a verified signature.
each package with a signature. Now is time for validate as the cluster(argocd PreSync hook) reject a package that canot verify.
5. Reproducing the rejection
The most accurate way to test this is to run exactly what the actual hook runs—in an isolated Job, using the same identity and trust policy—while pointing to a digest that never existed.
# verify-rejection-test.yaml apiVersion: batch/v1 kind: Job metadata: name: verify-rejection-test namespace: argocd spec: backoffLimit: 0 template: spec: serviceAccountName: manifests-verifier # the same sa restartPolicy: Never containers: - name: notation-verify image: public.ecr.aws/amazonlinux/amazonlinux:2023 env: - name: AWS_REGION value: "us-east-1" command: ["/bin/bash", "-c"] args: - | set -e dnf install -y tar gzip aws-cli >/dev/null BASE="https://d2hvyiie56hcat.cloudfront.net/linux/amd64/installer" curl -fsSL "$BASE/rpm/latest/aws-signer-notation-cli_amd64.rpm" -o /tmp/signer-notation.rpm rpm -U /tmp/signer-notation.rpm mkdir -p "$HOME/.docker" TOKEN=$(aws ecr get-login-password --region "$AWS_REGION") AUTH=$(printf 'AWS:%s' "$TOKEN" | base64 -w0) printf '{"auths":{"%s":{"auth":"%s"}}}' "700922282251.dkr.ecr.us-east-1.amazonaws.com" "$AUTH" > "$HOME/.docker/config.json" # la MISMA trust policy que usa el hook real — mismo registryScope, mismo signing profile cat > /tmp/trust-policy.json <<POLICY { "version": "1.0", "trustPolicies": [{ "name": "manifests", "registryScopes": ["700922282251.dkr.ecr.us-east-1.amazonaws.com/kcl-modules/manifests"], "signatureVerification": { "level": "strict" }, "trustStores": ["signingAuthority:aws-signer-ts"], "trustedIdentities": ["arn:aws:signer:us-east-1:700922282251:/signing-profiles/platform_95a9345572361278019b080e5e"] }] } POLICY notation policy import --force /tmp/trust-policy.json # un digest con formato valido (64 hex chars) que jamas se pusheo a ECR FAKE_DIGEST="sha256:1fb9d6b6976c4ef24c81e83fec13605406a0e7bd0430ab8657c6deb249fake" echo "Intentando verificar un digest que nunca existio: $FAKE_DIGEST" notation verify "700922282251.dkr.ecr.us-east-1.amazonaws.com/kcl-modules/manifests@$FAKE_DIGEST" apply and validate:
segoja7@renderer:~$ kubectl apply -f verify-rejection-test.yaml job.batch/verify-rejection-test created segoja7@renderer:~$ kubectl logs -n argocd verify-rejection-test-g99h4 Warning: existing trust policy configuration file will be overwritten Trust policy configuration imported successfully. Intentando verificar un digest que nunca existio: sha256:1fb9d6b6976c4ef24c81e83fec13605406a0e7bd0430ab8657c6deb249d4fake Error: "700922282251.dkr.ecr.us-east-1.amazonaws.com/kcl-modules/manifests@sha256:1fb9d6b6976c4ef24c81e83fec13605406a0e7bd0430ab8657c6deb249d4fake": invalid reference: invalid digest "sha256:1fb9d6b6976c4ef24c81e83fec13605406a0e7bd0430ab8657c6deb249d4fake": invalid checksum digest format. Expecting <registry>/<repository>:<tag> or <registry>/<repository>@<digest> The Job ended in error (1 failed) exactly what the actual PreSync hook would do against any digest it cannot verify. According to ArgoCD's documented behavior, a failed PreSync hook aborts the entire sync: nothing is applied.
CONCLUSION:
While AWS Signer signature our package OCI in ECR, argocd in EKS cluster only runs tamper-proof packages, we must remember a fundamental rule: just because a package is signed doesn't mean it's secure. A signature only guarantees origin and integrity. To genuinely secure the entire deployment lifecycle, adopting supply chain frameworks like SLSA is the necessary next step.








