Kubernetes Ingress
Guard your Kubernetes ingress with Kanidm authentication and authorization.
Prerequisites
We recommend you have the following before continuing:
- Kanidm
- Kubernetes v1.23 or above
- Nginx Ingress
- A fully qualified domain name with an A record pointing to your k8s ingress.
- CertManager with a Cluster Issuer installed.
Instructions
-
Create a Kanidm account and group:
- Create a Kanidm account. Please see the section Creating Accounts.
- Give the account a password. Please see the section Resetting Account Credentials.
- Make the account a person. Please see the section People Accounts.
- Create a Kanidm group. Please see the section Creating Accounts.
- Add the account you created to the group you create.
-
Create a Kanidm OAuth2 resource:
- Create the OAuth2 resource for your domain. Please see the section Create the Kanidm Configuration.
- Add a scope mapping from the resource you created to the group you create with the openid, profile, and email scopes. Please see the section Create the Kanidm Configuration.
-
Create a
Cookie Secret
to for the placeholder<COOKIE_SECRET>
in step 4:docker run -ti --rm python:3-alpine python -c 'import secrets,base64; print(base64.b64encode(base64.b64encode(secrets.token_bytes(16))).decode("utf-8"));'
-
Create a file called
k8s.kanidm-nginx-auth-example.yaml
with the block below. Replace every<string>
(drop the<>
) with appropriate values:<FQDN>
: The fully qualified domain name with an A record pointing to your k8s ingress.<KANIDM_FQDN>
: The fully qualified domain name of your Kanidm deployment.<COOKIE_SECRET>
: The output from step 3.<OAUTH2_RS_NAME>
: Please see the output from step 2.1 or get the OAuth2 resource you create from that step.<OAUTH2_RS_BASIC_SECRET>
: Please see the output from step 2.1 or get the OAuth2 resource you create from that step.
This will deploy the following to your cluster:
- modem7/docker-starwars - An example web site.
- OAuth2 Proxy - A OAuth2 proxy is used as an OAuth2 client with NGINX Authentication Based on Subrequest Result.
--- apiVersion: v1 kind: Namespace metadata: name: kanidm-example labels: pod-security.kubernetes.io/enforce: restricted --- apiVersion: apps/v1 kind: Deployment metadata: namespace: kanidm-example name: website labels: app: website spec: revisionHistoryLimit: 1 replicas: 1 selector: matchLabels: app: website template: metadata: labels: app: website spec: containers: - name: website image: modem7/docker-starwars imagePullPolicy: Always ports: - containerPort: 8080 securityContext: allowPrivilegeEscalation: false capabilities: drop: ["ALL"] securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault --- apiVersion: v1 kind: Service metadata: namespace: kanidm-example name: website spec: selector: app: website ports: - protocol: TCP port: 8080 targetPort: 8080 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: cert-manager.io/cluster-issuer: lets-encrypt-cluster-issuer nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth" nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri" name: website namespace: kanidm-example spec: ingressClassName: nginx tls: - hosts: - <FQDN> secretName: <FQDN>-ingress-tls # replace . with - in the hostname rules: - host: <FQDN> http: paths: - path: / pathType: Prefix backend: service: name: website port: number: 8080 --- apiVersion: apps/v1 kind: Deployment metadata: labels: k8s-app: oauth2-proxy name: oauth2-proxy namespace: kanidm-example spec: replicas: 1 selector: matchLabels: k8s-app: oauth2-proxy template: metadata: labels: k8s-app: oauth2-proxy spec: containers: - args: - --provider=oidc - --email-domain=* - --upstream=file:///dev/null - --http-address=0.0.0.0:4182 - --oidc-issuer-url=https://<KANIDM_FQDN>/oauth2/openid/<OAUTH2_RS_NAME> - --code-challenge-method=S256 env: - name: OAUTH2_PROXY_CLIENT_ID value: <OAUTH2_RS_NAME> - name: OAUTH2_PROXY_CLIENT_SECRET value: <OAUTH2_RS_BASIC_SECRET> - name: OAUTH2_PROXY_COOKIE_SECRET value: <COOKIE_SECRET> image: quay.io/oauth2-proxy/oauth2-proxy:latest imagePullPolicy: Always name: oauth2-proxy ports: - containerPort: 4182 protocol: TCP securityContext: allowPrivilegeEscalation: false capabilities: drop: ["ALL"] securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault --- apiVersion: v1 kind: Service metadata: labels: k8s-app: oauth2-proxy name: oauth2-proxy namespace: kanidm-example spec: ports: - name: http port: 4182 protocol: TCP targetPort: 4182 selector: k8s-app: oauth2-proxy --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: oauth2-proxy namespace: kanidm-example spec: ingressClassName: nginx rules: - host: <FQDN> http: paths: - path: /oauth2 pathType: Prefix backend: service: name: oauth2-proxy port: number: 4182 tls: - hosts: - <FQDN> secretName: <FQDN>-ingress-tls # replace . with - in the hostname
-
Apply the configuration by running the following command:
kubectl apply -f k8s.kanidm-nginx-auth-example.yaml
-
Check your deployment succeeded by running the following commands:
kubectl -n kanidm-example get all kubectl -n kanidm-example get ingress kubectl -n kanidm-example get Certificate
You may use kubectl's describe and log for troubleshooting. If there are ingress errors see the Ingress NGINX documentation's troubleshooting page. If there are certificate errors see the CertManger documentation's troubleshooting page.
Once it has finished deploying, you will be able to access it at
https://<FQDN>
which will prompt you for authentication.
Cleaning Up
-
Remove the resources create for this example from k8s:
kubectl delete namespace kanidm-example
-
Remove the objects created for this example from Kanidm:
- Delete the account created in section Instructions step 1.
- Delete the group created in section Instructions step 2.
- Delete the OAuth2 resource created in section Instructions step 3.