Skip to content

ministryofjustice/cloud-platform-terraform-gatekeeper

Repository files navigation

cloud-platform-terraform-gatekeeper

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.

Usage

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.

Adding a new constraint:

  1. Create a constraint template under the resources/constraint_templates folder
  2. Create a constraint file under the resources/constraints folder
  3. Update the constraint_map in the local block in the constraints/locals.tf file
  4. Update the dryrun_map variable in the variables.tf and constraints/variables.tf files
  5. Update the dryrun_map variable in the test/unit-test/main.tf file
  6. Update the dryrun_map variable in the example/main.tf file

Configuring constraints

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.

Caveats:

  • 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

Testing

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

Requirements

Name Version
terraform >= 0.14
kubectl 1.10.0

Providers

Name Version
helm n/a
kubectl 1.10.0
kubernetes n/a

Modules

No modules.

Resources

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

Inputs

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

Outputs

No outputs.

Tags

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

Reading Material

What is OPA Gatekeeper? OPA Gatekeeper Library