Container Scanning and Signing using Trivy and Kyverno
In the world of cloud-native applications, container security is paramount. Ensuring that your container images are free of vulnerabilities before deployment is a critical step in maintaining a secure environment. In this post, we'll walk through the process of scanning container images using Trivy, signing them with Cosign upon successful scans, and enforcing these policies during deployment in Amazon EKS using Kyverno.
Prerequisites:
Before we start, ensure you have the following tools and services configured:
Docker: For building and managing container images.
Trivy: A vulnerability scanner for containers.
Cosign: A tool for signing and verifying container images.
Kyverno: A Kubernetes policy engine.
Amazon EKS: An Amazon Elastic Kubernetes Service cluster.
Step 1: Build Your Container Image
First, let's build a simple container image. Create a Dockerfile:
# Dockerfile
FROM alpine:latest
RUN apk --no-cache add curl
CMD ["curl", "--version"]
Build the image:
docker build -t registry-name/alpine-curl:latest .
Step 2: Scan the Image with Trivy
Next, we need to scan the image for vulnerabilities using Trivy.
trivy image registry-name/alpine-curl:latest
Step 3: Sign the Image with Cosign
Once the image is free of vulnerabilities (or has accepted exceptions), you can sign it using Cosign.
Generate a key pair if you don't have one:
cosign generate-key-pair
Get the SHA of the image:
docker inspect --format='{{.RepoDigests}}' registry-name/alpine-curl:latest
Sign the image:
cosign sign --key cosign.key registry-name/alpine-curl@sha256:<unique finger print here>
Verify the signature:
cosign verify --key cosign.pub registry-name/alpine-curl:latest
In the above example, the public Rekor server at https://rekor.sigstore.dev/ will be utilized for storing the transparency log (metadata).
In a scenario that includes a private container registry, there is no requirement to push the metadata to a public Rekor server during setup. Therefore, in such cases, this flag can be used to disable the feature during the signing process.
--tlog-upload=false
Sign the image:
cosign sign --key cosign.key --tlog-upload=false registry-name/alpine-curl@sha256:<unique finger print here>
Verify the signature:
cosign verify --key cosign.pub --insecure-ignore-tlog=true regsirt-name/alpine-curl:latest
Please be aware that enabling the above flags will fully deactivate transparency log and its validation. In case of a private and air-gapped deployment, utilizing these flags can simplify the setup. Yet, if transparency logs are also required, it is recommended to establish a private instance of the Rekor server. The following Github issues can assist you in making an informed decision on this matter.
Step 4: Create a Kyverno Policy
To enforce that only signed images are deployed in your EKS cluster, create a Kyverno policy. This policy will validate the presence of Cosign signatures on container images using the public key.
Create a policy file verify-image-signature.yaml:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
background: false
rules:
- name: check-image-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "registry-name/alpine-curl:*"
mutateDigest: true
attestors:
- count: 1
entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM
5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==
-----END PUBLIC KEY-----
rekor:
ignoreTlog: true
IgnoreTlog flag is used to ignore transperancy log validation from rekor server
MutateDigest option needs to be set for kyverno to fetch the sha for the corresponding image tag to validate.
More information on Kyverno policies can be found here https://kyverno.io/docs/writing-policies/verify-images/sigstore/
Step 5: Deploy the Kyverno Policy
Apply the Kyverno policy to your EKS cluster:
kubectl apply -f verify-image-signature.yaml
Step 6: Deploy the Application to EKS
Create a deployment file deployment.yaml for your application:
apiVersion: apps/v1
kind: Deployment
metadata:
name: alpine-curl-deployment
spec:
replicas: 1
selector:
matchLabels:
app: alpine-curl
template:
metadata:
labels:
app: alpine-curl
spec:
containers:
- name: alpine-curl
image: registry-name/alpine-curl:latest
Apply the deployment:
kubectl apply -f deployment.yaml
Sample notification for validation errors:
Error from server (Forbidden): error when creating "deployment.yaml": admission webhook "mutate.kyverno.svc" denied the request:
resource Deployment/default/alpine-curl-deployment was blocked due to the following policies
verify-image-signature:
check-image-signature: 'image verification failed for "your-username/alpine-curl:latest":
failed to verify signature, cosign verification failed for image "your-username/alpine-curl:latest":
no matching signatures:
spec:
containers:
- image: registry-name/alpine-curl:latest'
Conclusion
By integrating Trivy for vulnerability scanning, Cosign for signing images, and Kyverno for enforcing image policies, you create a robust security pipeline for your containerized applications. This workflow ensures that only secure and verified images are deployed in your EKS cluster, significantly enhancing your container security posture.
Next Steps
Automate the Workflow: Integrate this process into your CI/CD pipeline for automated signing based on vulnerability feedback from Trivy or the scanning tool of your preference like Prisma Cloud, Snyk, Wiz, AquaSec etc.
Continuous Monitoring: Keep a constant watch on your Kyverno policies and deployed containers to ensure that the validation is occurring correctly.
By following these practices, you'll be well on your way to maintaining a secure and compliant container environment.
Kommentare