--- title: "Tutorial: Ingress Validation" kind: kubernetes weight: 10 --- This tutorial shows how to deploy OPA as an admission controller from scratch. For the purpose of the tutorial we will deploy two policies that ensure: - Ingress hostnames must be whitelisted on the Namespace containing the Ingress. - Two ingresses in different namespaces must not have the same hostname. ## Prerequisites This tutorial requires Kubernetes 1.9 or later. To run the tutorial locally, we recommend using [minikube](https://kubernetes.io/docs/getting-started-guides/minikube) in version `v0.28+` with Kubernetes 1.10 (which is the default). ## Steps ### 1. Start Kubernetes recommended Admisson Controllers enabled To implement admission control rules that validate Kubernetes resources during create, update, and delete operations, you must enable the [ValidatingAdmissionWebhook](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#validatingadmissionwebhook) when the Kubernetes API server is started. The ValidatingAdmissionWebhook admission controller is included in the [recommended set of admission controllers to enable](https://kubernetes.io/docs/admin/admission-controllers/#is-there-a-recommended-set-of-admission-controllers-to-use) Start minikube: ```bash minikube start ``` Make sure that the minikube ingress addon is enabled: ```bash minikube addons enable ingress ``` ### 2. Create a new Namespace to deploy OPA into When OPA is deployed on top of Kubernetes, policies are automatically loaded out of ConfigMaps in the `opa` namespace. ```bash kubectl create namespace opa ``` Configure `kubectl` to use this namespace: ```bash kubectl config set-context opa-tutorial --user minikube --cluster minikube --namespace opa kubectl config use-context opa-tutorial ``` ### 3. Deploy OPA on top of Kubernetes Communication between Kubernetes and OPA must be secured using TLS. To configure TLS, use `openssl` to create a certificate authority (CA) and certificate/key pair for OPA: ```bash openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -days 100000 -out ca.crt -subj "/CN=admission_ca" ``` Generate the TLS key and certificate for OPA: ```bash cat >server.conf < Note: the Common Name value you give to openssl MUST match the name of the OPA service created below. Create a Secret to store the TLS credentials for OPA: ```bash kubectl create secret tls opa-server --cert=server.crt --key=server.key ``` Next, use the file below to deploy OPA as an admission controller. **`admission-controller.yaml`**: ``` # Grant OPA/kube-mgmt read-only access to resources. This lets kube-mgmt # replicate resources into OPA so they can be used in policies. kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: opa-viewer roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io subjects: - kind: Group name: system:serviceaccounts:opa apiGroup: rbac.authorization.k8s.io --- # Define role for OPA/kube-mgmt to update configmaps with policy status. kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: opa name: configmap-modifier rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["update", "patch"] --- # Grant OPA/kube-mgmt role defined above. kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: opa name: opa-configmap-modifier roleRef: kind: Role name: configmap-modifier apiGroup: rbac.authorization.k8s.io subjects: - kind: Group name: system:serviceaccounts:opa apiGroup: rbac.authorization.k8s.io --- kind: Service apiVersion: v1 metadata: name: opa namespace: opa spec: selector: app: opa ports: - name: https protocol: TCP port: 443 targetPort: 443 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: app: opa namespace: opa name: opa spec: replicas: 1 selector: matchLabels: app: opa template: metadata: labels: app: opa name: opa spec: containers: # WARNING: OPA is NOT running with an authorization policy configured. This # means that clients can read and write policies in OPA. If you are # deploying OPA in an insecure environment, be sure to configure # authentication and authorization on the daemon. See the Security page for # details: https://www.openpolicyagent.org/docs/security.html. - name: opa image: openpolicyagent/opa:{{< current_docker_version >}} args: - "run" - "--server" - "--tls-cert-file=/certs/tls.crt" - "--tls-private-key-file=/certs/tls.key" - "--addr=0.0.0.0:443" - "--addr=http://127.0.0.1:8181" - "--log-format=json-pretty" - "--set=decision_logs.console=true" volumeMounts: - readOnly: true mountPath: /certs name: opa-server readinessProbe: httpGet: path: /health scheme: HTTPS port: 443 initialDelaySeconds: 3 periodSeconds: 5 livenessProbe: httpGet: path: /health scheme: HTTPS port: 443 initialDelaySeconds: 3 periodSeconds: 5 - name: kube-mgmt image: openpolicyagent/kube-mgmt:0.8 args: - "--replicate-cluster=v1/namespaces" - "--replicate=extensions/v1beta1/ingresses" volumes: - name: opa-server secret: secretName: opa-server --- kind: ConfigMap apiVersion: v1 metadata: name: opa-default-system-main namespace: opa data: main: | package system import data.kubernetes.admission main = { "apiVersion": "admission.k8s.io/v1beta1", "kind": "AdmissionReview", "response": response, } default response = {"allowed": true} response = { "allowed": false, "status": { "reason": reason, }, } { reason = concat(", ", admission.deny) reason != "" } ``` ```bash kubectl apply -f admission-controller.yaml ``` When OPA starts, the `kube-mgmt` container will load Kubernetes Namespace and Ingress objects into OPA. You can configure the sidecar to load any kind of Kubernetes object into OPA. The sidecar establishes watches on the Kubernetes API server so that OPA has access to an eventually consistent cache of Kubernetes objects. Next, generate the manifest that will be used to register OPA as an admission controller. This webhook will ignore any namespace with the label `openpolicyagent.org/webhook=ignore`. ```bash cat > webhook-configuration.yaml <