{"id":18481333,"url":"https://github.com/ukhomeoffice/policy-admission","last_synced_at":"2025-04-08T16:31:56.035Z","repository":{"id":26115743,"uuid":"106173696","full_name":"UKHomeOffice/policy-admission","owner":"UKHomeOffice","description":"Kubernetes admission controller","archived":false,"fork":false,"pushed_at":"2024-01-12T15:13:39.000Z","size":442,"stargazers_count":16,"open_issues_count":6,"forks_count":5,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-03-23T16:39:17.926Z","etag":null,"topics":["admission-controllers","kubernetes","security"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/UKHomeOffice.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-10-08T12:14:32.000Z","updated_at":"2024-09-13T18:51:42.000Z","dependencies_parsed_at":"2024-01-18T09:04:33.330Z","dependency_job_id":"e10a4ebc-fa7b-452e-b42a-3953f93cd2d1","html_url":"https://github.com/UKHomeOffice/policy-admission","commit_stats":null,"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UKHomeOffice%2Fpolicy-admission","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UKHomeOffice%2Fpolicy-admission/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UKHomeOffice%2Fpolicy-admission/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/UKHomeOffice%2Fpolicy-admission/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/UKHomeOffice","download_url":"https://codeload.github.com/UKHomeOffice/policy-admission/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247882122,"owners_count":21011998,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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-controllers","kubernetes","security"],"created_at":"2024-11-06T12:23:16.815Z","updated_at":"2025-04-08T16:31:55.274Z","avatar_url":"https://github.com/UKHomeOffice.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## **Kubernetes Policy Admission Controller**\n\nThe [policy-admission](https://github.com/UKHomeOffice/policy-admission) is a [custom admission controller](https://kubernetes.io/docs/admin/extensible-admission-controllers/) used to enforce a collection of security and administrative policies across our kubernetes clusters. Each of the authorizers (https://github.com/UKHomeOffice/policy-admission/tree/master/pkg/authorize) are enabled individually via the command option --authorizer=NAME:CONFIG_PATH (note if no configuration path is given we use the default configuration for that authorizer).\n\n```shell\n$ bin/policy-admission --help\nNAME:\n   policy-admission - is a service used to enforce security policy within a cluster\n\nUSAGE:\n    [global options] command [command options] [arguments...]\n\nVERSION:\n   v0.1.0 (git+sha: fa934ac)\n\nAUTHOR:\n   Rohith Jayawardene \u003cgambol99@gmail.com\u003e\n\nCOMMANDS:\n     help, h  Shows a list of commands or help for one command\n\nGLOBAL OPTIONS:\n   --listen INTERFACE      network interface the service should listen on INTERFACE (default: \":8443\") [$LISTEN]\n   --tls-cert PATH         path to a file containing the tls certificate PATH [$TLS_CERT]\n   --tls-key PATH          path to a file containing the tls key PATH [$TLS_KEY]\n   --authorizer value      enable an admission authorizer, the format is name=config_path (i.e images=config.yaml)\n   --cluster NAME          the name of the kubernetes cluster we are running NAME [$KUBE_CLUSTER]\n   --namespace NAME        namespace to create denial events (optional as we can try and discover) NAME (default: \"kube-admission\") [$KUBE_NAMESPACE]\n   --slack-webhook URL     slack webhook to send the events to URL [$SLACK_WEBHOOK]\n   --controller-name NAME  controller name also used as prefix in annotations NAME (default: \"policy-admission.acp.homeoffice.gov.uk\") [$CONTROLLER_NAME]\n   --enable-logging BOOL   indicates you wish to log the admission requests for debugging BOOL [$ENABLE_LOGGING]\n   --enable-metrics BOOL   indicates you wish to expose the prometheus metrics BOOL [$ENABLE_METRICS]\n   --enable-events BOOL    indicates you wish to log kubernetes events on denials BOOL [$ENABLE_EVENTS]\n   --rate-limit DURATION   the time duration to attempt to wrap up duplicate events DURATION (default: 1m30s) [$RATE_LIMIT]\n   --verbose BOOL          indicates you wish for verbose logging BOOL [$VERBOSE]\n   --help, -h              show help\n   --version, -v           print the version\n```\n\nNote, the configuration is auto-reloaded, so you can chunk the configuration files in the [configmap](https://kubernetes.io/docs/tasks/configure-pod-container/configmap/) and on changes the authorizer will automatically pick on the changes.\n\n### **Prometheus Metrics**\nThe admission controller on `/metrics` on the listening port produce a series of metrics related to request approvals and denial and a breakdown of the latency per authorizer and request. The feature is enabled via `--enable-metrics` _(albeit defaulting to true)_.\n\n### **Slack Integration**\n\nThe admission controller along with creating kubernetes events in specified namespace _(via the `--enable-events` command line option)_ can also publish denial to a slack channel. Simply pass the `--slack-webhook` or inject the `SLACK_WEBHOOK` environment variable. This event will detail Kind, Name, Namespace, Username and the denial message in the event.\n\n### **Authorizers**\n\nAn authorizer is enabled via the command line switch `--authorizer=name=config_file_path` i.e. `--authorizer=images=/config/images.yml`. The configuration as well as the defaults for all of these can be found in the `doc.go` in each of the authorizer folders. Each of the authorizer's can be configured to ignore certain namespaces.\n\nInitially the project started off with a series of authorizer's however when the `scripts` authorizer was added _most_ of coded authorizer's could be replaced with a script.\n\n#### **- Scripts Authorizer**\n\nThe scripts authorizer _(--authorizer=scripts=config)_ provides an embedded javascript runtime via [github.com/robertkrimen/otto](https://github.com/robertkrimen/otto). Both the object and namespace it derives is inject into the script as a javascript object. An explain before for an Ingress resource\n\n```Javascript\nfunction isFiltering(o) {\n  if (o.kind != \"Ingress\") {\n    return false\n  }\n  annotations = o.metadata.annotations\n  if (annotations[\"ingress.kubernetes.io/class\"] != \"default\") {\n    return false\n  }\n\n  return true\n}\n\nif (isFiltering(object)) {\n  // do some logic\n  provider = object.metadata.annotations[\"ingress.kubernetes.io/provider\"]\n  if (provider != \"http\") {\n    deny(\"metadata.annotations[ingress.kubernetes.io/provider]\", \"you must use a http provider\", provider)\n  }\n}\n```\n\nYou can find a few more examples in the [features folder](https://github.com/UKHomeOffice/policy-admission/tree/master/pkg/authorize/scripts/features). By default everyone is allowed, if you wish to deny and object, you can call the `deny` method, passing the field and reason for denial.\n\n#### **- Images**\n\nImages provides a means to control which container images are permitted to run within the environment. Applied to both the `initContainers` and `containers` of any pods which are created. The configuration for authorizer contains a series of regex's, which are taken as the default policy, however it will also read the annotation `policy-admission.acp.homeoffice.gov.uk/images` on the pod namespace; a comma separated list of regex's which can add on top of the default policies.\n\n```YAML\napiVersion: v1\nkind: Namespace\nmetadata:\n  name: test\n  annotations:\n    policy-admission.acp.homeoffice.gov.uk/images: ^docker.io/ukhomehomeoffice/.*$, quay.io/ukhomehomeoffice/.*$\n```\n\n#### **- Domains**\n\nThe domains authorizer provides one a means to control which hostname's / site are permitted via ingress resources and to control those at a namespace level, ensuring pods from another namespace can't take over a URL from another hosted site. Namespaces are annotated with the `policy-admission.acp.homeoffice.gov.uk/domains` tag, which is a comma separated list of domains this namespace can create ingress resources for. This hostname's themselves may contain a single wildcard i.e. `*.example.com`\n\n#### **- Kube Cert Manager**\n\nThis authorizer is fairly bespoke, it was added as a number of users were getting the configuration wrong and causing the [kube cert manager](https://github.com/PalmStoneGames/kube-cert-manager) to fail and hit Letsencrypt limits. The authorizer performs a series of checks against a ingress resource which has been labelled to consume certificates from Letencrypt. This is broken down depending on internal or external ingress ELB's.\n\nFor internal:\n- we ensure it's not trying to use HTTP as the challenge and has selected dns.\n- we ensure the domain name is hosted by us and thus kube-cert-manager can add the TXT record.\n\nFor External:\n- we ensure the ingress is not attached to an internal ELB.\n- we ensure the resource if using DNS the zone is hosted by us.\n- we ensure if it's using HTTP that the hostname is a CNAME to our ingress ELB.\n\n#### **- Services**\n\nServices provides a means to control the kubernetes service types a namespace can use. In general we don't want anyone to be able to open `NodePorts` or `LoadBalancer` services. The authorizer takes the default configuration which is `ClusterIP` only and also reads the `policy-admission.acp.homeoffice.gov.uk/services` annotation from the namespace to see if anything else is permitted.\n\n#### **- Values**\n\nThe values is generic authorizer used to match one or more attributes targeted via jsonpath and regex the values against a regexp. It can be used to enforce certain labels or annotation's i.e. a namespace must have a contact label etc. The configuration is as below\n\n```YAML\nfilter-on: Ingress\nmatches:\n- path: metadata.annotations\n  key-filter: ingress.kubernetes.io/provider\n  value: ^http$\n## OR on a namespace\nfilter-on: Namespace\nmatches:\n- path: metadata.annotations\n  key-filter: maintainers\n  value: ^.*$\n  required: true\n```\n#### **- Toleration's \u0026 Taints**\n\nThe current pod tolerations admission gave more headache then features so we combined the enforcement into an authorizer. The behaviors is as such.\n\n* Check the pod tolerations against the default whitelist defined in the configuration.\n* If an annotation exists on the namespace, check the pod against the whitelist\n\nThe configuration for the authorizer is\n\n```go\n// Config is the configuration for the taint authorizer\ntype Config struct {\n\t// IgnoreNamespaces is list of namespace to\n\tIgnoreNamespaces []string `yaml:\"ignored-namespaces\" json:\"ignored-namespaces\"`\n\t// DefaultWhitelist is default whitelist applied to all unless a namespace has one\n\tDefaultWhitelist []core.Toleration `yaml:\"default-whitelist\" json:\"default-whitelist\"`\n}\n```\n\nAn example configuration is;\n\n```YAML\nignored-namespaces:\n- kube-admission\n- kube-system\n- logging\n- sysdig-agent\ndefault-whitelist:\n- key: node.alpha.kubernetes.io/notReady\n  operator: '*'\n  value: '*'\n  effect: '*'\n- key: node.alpha.kubernetes.io/unreachable\n  operator: '*'\n  value: '*'\n  effect: '*'\n- key: dedicated\n  operator: '*'\n  value: backend\n  effect: '*'\n- key: dedicated\n  operator: '*'\n  value: liberal\n  effect: '*'\n- key: dedicated\n  operator: '*'\n  value: strict\n  effect: '*'\n```\n\nFor the namespace whitelist annotation the tolerations must be specified in json for:\n\n```YAML\napiVersion: v1\nkind: Namespace\nmetadata:\n  name: test\n  annotations:\n    policy-admission.acp.homeoffice.gov.uk/tolerations: |\n      [\n        {\n          \"key\": \"dedicated\",\n          \"operator\": \"*\",\n          \"value\": \"compute\",\n          \"effect\": \"*\"\n        },\n        {\n          \"key\": \"dedicated\",\n          \"operator\": \"*\",\n          \"value\": \"liberal\",\n          \"effect\": \"*\"\n        },\n        {\n          \"key\": \"dedicated\",\n          \"operator\": \"*\",\n          \"value\": \"strict\",\n          \"effect\": \"*\"\n        }\n      ]\n```\n\n#### **Controller Name**\n\nYou can alter the controller prefix by using the `--controller-name` option which sets the prefix for the annotations across all the authorizers.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fukhomeoffice%2Fpolicy-admission","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fukhomeoffice%2Fpolicy-admission","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fukhomeoffice%2Fpolicy-admission/lists"}