Kubernetes native security policy enforcement, an upgrade of https://github.com/ministryofjustice/cloud-platform-terraform-opa
Kubernetes allows decoupling policy decisions from the API server by means of admission controller webhooks to intercept admission requests before they are persisted as objects in Kubernetes. Gatekeeper is a customizable admission webhook for Kubernetes that enforces policies executed by the Open Policy Agent (OPA), a policy engine for Cloud Native environments hosted by CNCF.
The order which resources are created are important, to control resource creation order constraint_templates
and constraints
are broken into sub-modules.
A downside of this approach, is that you have to pass variables twice (small amount of "dry"), once into the parent module and then again to the constraints module. However, the benefits are that we can easily create constraints and templates with terraform loops and control resource creation order.
- Create a constraint template under the
resources/constraint_templates
folder - Create a constraint file under the
resources/constraints
folder - Update the
constraint_map
in the local block in theconstraints/locals.tf
file - Update the
dryrun_map
variable in thevariables.tf
andconstraints/variables.tf
files - Update the
dryrun_map
variable in thetest/unit-test/main.tf
file - Update the
dryrun_map
variable in theexample/main.tf
file
The constraint template design allows you to define a template and then instantiate different constraints from that template.
Constraints are flexible and can take input variables, the best way to configure these parameters from terraform values is through constraints/locals.tf
.
In constraints/locals.tf
we read the constraint from yaml and convert it to json so you can change values and add new keys easily. We convert this back into yaml for terraform to apply as a k8s manifest.
- to generate the audit report, it seems advisable to query a cache of filtered K8s objects, rather than hit the API each time (60 sec intervals default); because of that any kind used by a constraint template must also be added to the sync config at the end of constraints.tf
- deleting a ConstraintTemplate that still has Constraints breaks things badly; only deleting the CRDs (which in turn removes all the constraints) unblocks again
- no colons (:) in the description field
gatekeeper provides a neat cli tool for testing. Once installed you can run the following command to verify the test suite has the expected violations:
gator verify test/suite/...
When adding new tests, test data goes under their own dir test/suite/samples/test_suite_name/
, case.yaml
contains config for the resource being tested, inventory.yaml
contains config for 'mock resources', and the test suite file can be found in test/suite/test_suite_name.yaml
, see diagram below:
test/suite
├── samples/
│ └── test_suite_name/
│ ├── case_description_1/
│ │ ├── case.yaml
│ │ └── inventory.yaml
│ └── case_description_2
│ ├── case.yaml
│ └── inventory.yaml
└── test_suite_name.yaml
Name | Version |
---|---|
terraform | >= 0.14 |
kubectl | 1.10.0 |
Name | Version |
---|---|
helm | n/a |
kubectl | 1.10.0 |
kubernetes | n/a |
No modules.
Name | Type |
---|---|
helm_release.gatekeeper | resource |
kubectl_manifest.config-sync | resource |
kubectl_manifest.unique-ingress-constraint | resource |
kubectl_manifest.unique-ingress-template | resource |
kubernetes_namespace.gatekeeper | resource |
Name | Description | Type | Default | Required |
---|---|---|---|---|
cluster_domain_name | The cluster domain used for externalDNS annotations and certmanager | any |
n/a | yes |
define_constraints | if false, only the app is deployed, no constraints | bool |
true |
no |
No outputs.
Some of the inputs are tags. All infrastructure resources need to be tagged according to the MOJ techincal guidance. The tags are stored as variables that you will need to fill out as part of your module.
Name | Description | Type | Default | Required |
---|---|---|---|---|
application | string | - | yes | |
business-unit | Area of the MOJ responsible for the service | string | mojdigital |
yes |
environment-name | string | - | yes | |
infrastructure-support | The team responsible for managing the infrastructure. Should be of the form team-email | string | - | yes |
is-production | string | false |
yes | |
team_name | string | - | yes | |
sqs_name | string | - | yes |