{"id":42389738,"url":"https://github.com/eric-carlsson/pod-image-policy","last_synced_at":"2026-02-01T13:02:51.025Z","repository":{"id":329654880,"uuid":"1120313983","full_name":"eric-carlsson/pod-image-policy","owner":"eric-carlsson","description":"A Kubernetes admission controller that validates and mutates container image references in pods.","archived":false,"fork":false,"pushed_at":"2026-01-28T10:07:18.000Z","size":97,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-28T10:21:37.441Z","etag":null,"topics":["admission","container","image","kubernetes","mutation","validation","webhook"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eric-carlsson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-20T23:55:03.000Z","updated_at":"2026-01-28T10:06:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/eric-carlsson/pod-image-policy","commit_stats":null,"previous_names":["eric-carlsson/pod-image-policy"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/eric-carlsson/pod-image-policy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eric-carlsson%2Fpod-image-policy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eric-carlsson%2Fpod-image-policy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eric-carlsson%2Fpod-image-policy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eric-carlsson%2Fpod-image-policy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eric-carlsson","download_url":"https://codeload.github.com/eric-carlsson/pod-image-policy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eric-carlsson%2Fpod-image-policy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28978730,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-01T12:13:08.691Z","status":"ssl_error","status_checked_at":"2026-02-01T12:13:08.356Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["admission","container","image","kubernetes","mutation","validation","webhook"],"created_at":"2026-01-27T23:54:56.607Z","updated_at":"2026-02-01T13:02:51.020Z","avatar_url":"https://github.com/eric-carlsson.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pod-image-policy\n\nA Kubernetes admission controller that validates and mutates container image references in pods.\n\n## Features\n\n- Validate image segments with allow/deny/warn actions and custom messages.\n- Rewrite image segments using regex capture groups and replacement templates with optional messages.\n\n### Examples\n\n- Reject images with `latest` tag:\n\n  ```yaml\n  validate:\n    rules:\n      - match:\n          tag: \"latest\"\n        action: deny\n        message: \"'latest' image tags are not allowed\"\n  ```\n\n- Warn when using release candidates:\n\n  ```yaml\n  validate:\n    rules:\n      - match:\n          tag: \".*-rc.*\"\n        action: warn\n        message: \"prefer using stable releases over release candidates\"\n  ```\n\n- Rewrite all public Docker Hub images to use a private mirror: `docker.io/library/\u003cimage\u003e` (or `\u003cimage\u003e`) \u0026rarr; `registry.private/mirror/library/\u003cimage\u003e`:\n\n  ```yaml\n  mutate:\n    rules:\n      - match:\n          registry: \"docker\\.io\"\n          repository: \"library/(.*)\"\n        replace:\n          registry: \"registry.private\"\n          repository: \"mirror/library/${1}\"\n  ```\n\n- Rewrite specific images that have been moved to new repositories: `registry.io/team/app:v1` \u0026rarr; `registry.io/project/app:v1`:\n\n  ```yaml\n  mutate:\n    rules:\n      - match:\n          registry: \"registry\\.io\"\n          repository: \"team/(.*)\"\n        replace:\n          repository: \"project/${1}\"\n        message: \"'team/' repositories have been moved to 'project/'\"\n  ```\n\n## Deploy\n\nThe Helm chart is available as an OCI artifact at `oci://ghcr.io/eric-carlsson/charts/pod-image-policy`.\n\nA TLS certificate is required to enable communication between the API server and the webhook. By default, the chart is configured with a [cert-manager](https://cert-manager.io/docs/) integration that automatically creates a self-signed issuer and TLS certificate. This can be disabled if you want to bring your own TLS certificate.\n\n### With cert-manager\n\nDeploy the Helm chart with default values. This enables the cert-manager integration and creates a self-signed issuer:\n\n```sh\nhelm upgrade pod-image-policy oci://ghcr.io/eric-carlsson/charts/pod-image-policy \\\n  --install \\\n  --namespace pod-image-policy \\\n  --create-namespace\n```\n\nTo use an existing cert-manager issuer instead of the self-signed one:\n\n```sh\nhelm upgrade pod-image-policy oci://ghcr.io/eric-carlsson/charts/pod-image-policy \\\n  --install \\\n  --namespace pod-image-policy \\\n  --create-namespace \\\n  --set certManager.createSelfSignedIssuer=false \\\n  --set certManager.issuerRef.name=my-issuer \\\n  --set certManager.issuerRef.kind=ClusterIssuer\n```\n\n### Without cert-manager\n\nIf you prefer to manage certificates manually without cert-manager:\n\n1. Create namespace and TLS secret:\n\n   ```sh\n   kubectl create namespace pod-image-policy\n\n   openssl req -x509 -newkey rsa:2048 -nodes -days 365 \\\n     -keyout /tmp/tls.key -out /tmp/tls.crt \\\n     -subj \"/CN=pod-image-policy.pod-image-policy.svc\" \\\n     -addext \"subjectAltName=DNS:pod-image-policy.pod-image-policy.svc,DNS:pod-image-policy.pod-image-policy.svc.cluster.local\"\n\n   kubectl create secret tls pod-image-policy-tls \\\n     --cert=/tmp/tls.crt --key=/tmp/tls.key -n pod-image-policy\n   ```\n\n2. Deploy the Helm chart:\n\n   ```sh\n   helm upgrade pod-image-policy oci://ghcr.io/eric-carlsson/charts/pod-image-policy \\\n     --install \\\n     --namespace pod-image-policy \\\n     --set certManager.enabled=false \\\n     --set webhooks.mutating.caBundle=$(cat /tmp/tls.crt | base64 | tr -d '\\n') \\\n     --set webhooks.validating.caBundle=$(cat /tmp/tls.crt | base64 | tr -d '\\n') \\\n     --set-json 'volumes=[{\"name\":\"tls\",\"secret\":{\"secretName\":\"pod-image-policy-tls\"}}]' \\\n     --set-json 'volumeMounts=[{\"name\":\"tls\",\"mountPath\":\"/tls\",\"readOnly\":true}]' \\\n     --set-json 'args=[\"-certFile=/tls/tls.crt\",\"-keyFile=/tls/tls.key\"]'\n   ```\n\n### Custom policy configuration\n\nBy default, the webhook allows all images without mutations or restrictions. To enforce custom image policies, configure the `policy` value with your desired validation and mutation rules.\n\n`custom-values.yaml`:\n\n```yaml\npolicy:\n  mutate:\n    rules:\n      - match:\n          registry: \"docker\\.io\"\n          repository: \"library/(.*)\"\n        replace:\n          registry: \"registry.internal\"\n          repository: \"mirror/library/${1}\"\n        message: \"Image rewritten to use internal mirror\"\n  validate:\n    rules:\n      - match:\n          tag: \"latest\"\n        action: deny\n        message: \"'latest' tags are not allowed\"\n```\n\nDeploy:\n\n```sh\nhelm upgrade pod-image-policy oci://ghcr.io/eric-carlsson/charts/pod-image-policy \\\n  --install \\\n  --namespace pod-image-policy \\\n  --create-namespace \\\n  --values custom-values.yaml\n```\n\n## Policy reference\n\nThe admission controller is configured using a policy. The policy supports both validation and mutation actions.\n\n### Policy schema\n\n```yaml\nmutate:\n  rules:\n    - match: { \u003cmatch-fields\u003e }\n      replace: { \u003creplace-fields\u003e }\n      message: string # optional\nvalidate:\n  rules:\n    - match: { \u003cmatch-fields\u003e }\n      action: allow|warn|deny\n      message: string # optional\n```\n\n### Match fields\n\n| Field        | Description             |\n| ------------ | ----------------------- |\n| `registry`   | Image registry hostname |\n| `repository` | Repository path         |\n| `tag`        | Image tag               |\n| `digest`     | Image digest            |\n\nAll fields are optional regex patterns. Omitted fields match any value.\n\n**Pattern anchoring:**\n\n- Patterns without `^` or `$` are auto-anchored: `\"latest\"` → `\"^latest$\"`\n- Explicit anchors allow partial matching: `\"^v.*\"` matches version prefixes\n- Include any anchor to disable auto-anchoring\n\n### Replace fields\n\n| Field        | Description          |\n| ------------ | -------------------- |\n| `registry`   | New registry value   |\n| `repository` | New repository value |\n| `tag`        | New tag value        |\n| `digest`     | New digest value     |\n\nUse `${1}`, `${2}`, etc. to reference capture groups from match patterns.\n\n### Validation actions\n\n| Action  | Behavior                                           |\n| ------- | -------------------------------------------------- |\n| `allow` | Image permitted (no message shown)                 |\n| `warn`  | Image permitted with warning in admission response |\n| `deny`  | Image rejected; pod creation fails                 |\n\n**Evaluation:**\n\n- **Mutate**: First matching rule wins per image\n- **Validate**: All matching rules evaluated; any `deny` rejects the image immediately\n- Default action when no rules match: `allow`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feric-carlsson%2Fpod-image-policy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feric-carlsson%2Fpod-image-policy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feric-carlsson%2Fpod-image-policy/lists"}