-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# Keycloak | ||
|
||
Setup Kubernetes: | ||
``` | ||
minikube start --kubernetes-version v1.19.2 \ | ||
--feature-gates=ServiceAccountIssuerDiscovery=true \ | ||
--extra-config=apiserver.service-account-issuer=https://kubernetes.default.svc \ | ||
--extra-config apiserver.service-account-signing-key-file=/var/lib/minikube/certs/sa.key | ||
kubectl apply -f - <<EOF | ||
--- | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
kind: ClusterRoleBinding | ||
metadata: | ||
name: system:service-account-issuer-discovery | ||
roleRef: | ||
apiGroup: rbac.authorization.k8s.io | ||
kind: ClusterRole | ||
name: system:service-account-issuer-discovery | ||
subjects: | ||
- apiGroup: rbac.authorization.k8s.io | ||
kind: Group | ||
name: system:unauthenticated | ||
EOF | ||
``` | ||
|
||
Setup DNS record for `*.example.com` to `$( minikube ip )`. | ||
|
||
|
||
Nginx Ingress Controller: | ||
``` | ||
# create CA | ||
pcert create ca --ca | ||
pcert create server --with ca --server --dns *.example.com | ||
kubectl create ns ingress-nginx | ||
kubectl -n ingress-nginx create secret tls default-certificate --key server.key --cert server.crt | ||
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx | ||
helm install --namespace ingress-nginx ingress-nginx \ | ||
--set controller.hostPort.enabled=true \ | ||
--set controller.hostNetwork=true \ | ||
--set controller.kind=DaemonSet \ | ||
--set controller.admissionWebhooks.enabled=false \ | ||
--set controller.extraArgs.default-ssl-certificate="ingress-nginx/default-certificate" \ | ||
--set-string controller.config.force-ssl-redirect=true ingress-nginx/ingress-nginx | ||
``` | ||
|
||
Setup Keycloak: | ||
``` | ||
kubectl create ns keycloak | ||
kubectl apply -n keycloak -f keycloak.yaml | ||
``` | ||
|
||
Go to https://idp.example.com and login with user `admin` password `admin`. Under clients create a new client and enter the service account name as `Client ID` (e.g. `system:serviceaccount:default:default`). Configure the client as follows: | ||
* Settings (Tab) | ||
* Access Type: `bearer-only` | ||
* Credentials (Tab) | ||
* Authenticator: `Signed Jwt` | ||
* Use JWKS URL: `On` | ||
* JWKS URL: `https://kubernetes.default.svc/openid/v1/jwks` | ||
|
||
Get a projected token: | ||
``` | ||
kubectl create -f - <<EOF | ||
apiVersion: v1 | ||
kind: Pod | ||
metadata: | ||
name: read-token2 | ||
spec: | ||
restartPolicy: Never | ||
containers: | ||
- name: read-token | ||
image: busybox | ||
command: ['cat', '/var/run/secrets/tokens/service2'] | ||
volumeMounts: | ||
- mountPath: /var/run/secrets/tokens | ||
name: service2-token | ||
serviceAccountName: default | ||
volumes: | ||
- name: service2-token | ||
projected: | ||
sources: | ||
- serviceAccountToken: | ||
path: service2 | ||
expirationSeconds: 60000 | ||
audience: https://idp.example.com/auth/realms/master | ||
EOF | ||
``` | ||
|
||
``` | ||
token=$( kubectl logs read-token2 ) | ||
``` | ||
|
||
Get access token from token endpoint: | ||
``` | ||
$ curl -k https://idp.example.com/auth/realms/master/protocol/openid-connect/token \ | ||
--data grant_type=client_credentials \ | ||
--data client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \ | ||
--data client_assertion=$token | jq | ||
{ | ||
"error": "unauthorized_client", | ||
"error_description": "Client authentication with signed JWT failed: Missing ID on the token" | ||
} | ||
``` | ||
Does not work because the `jti` claim is not set by Kubernetes but required by Keycloak: | ||
* https://github.com/kubernetes/kubernetes/blob/cdec7e8b1faaba8f8bc3af1c5d256fd7433b5631/pkg/serviceaccount/claims.go#L61 | ||
* https://github.com/keycloak/keycloak/blob/12d824728882789de63b5dd19e5d8a4a6847ffda/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientSecretAuthenticator.java#L166 | ||
|
||
## Links | ||
* Keycloak Custom Authenticators: https://github.com/keycloak/keycloak-documentation/blob/master/server_development/topics/auth-spi.adoc#authentication-of-clients | ||
* Keycloak Example Authenticator: https://github.com/keycloak/keycloak/tree/master/examples/providers/authenticator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
--- | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: keycloak | ||
namespace: keycloak | ||
labels: | ||
app: keycloak | ||
spec: | ||
ports: | ||
- name: http | ||
port: 8080 | ||
targetPort: 8080 | ||
- name: https | ||
port: 8443 | ||
targetPort: 8443 | ||
selector: | ||
app: keycloak | ||
type: ClusterIP | ||
--- | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: keycloak | ||
namespace: keycloak | ||
labels: | ||
app: keycloak | ||
spec: | ||
replicas: 1 | ||
selector: | ||
matchLabels: | ||
app: keycloak | ||
template: | ||
metadata: | ||
labels: | ||
app: keycloak | ||
spec: | ||
containers: | ||
- name: keycloak | ||
image: quay.io/keycloak/keycloak:11.0.2 | ||
env: | ||
- name: KEYCLOAK_USER | ||
value: "admin" | ||
- name: KEYCLOAK_PASSWORD | ||
value: "admin" | ||
- name: PROXY_ADDRESS_FORWARDING | ||
value: "true" | ||
- name: X509_CA_BUNDLE | ||
value: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" | ||
ports: | ||
- name: http | ||
containerPort: 8080 | ||
- name: https | ||
containerPort: 8443 | ||
readinessProbe: | ||
httpGet: | ||
path: /auth/realms/master | ||
port: 8080 | ||
--- | ||
apiVersion: networking.k8s.io/v1 | ||
kind: Ingress | ||
metadata: | ||
name: keycloak | ||
namespace: keycloak | ||
annotations: | ||
nginx.ingress.kubernetes.io/backend-protocol: HTTPS | ||
spec: | ||
tls: | ||
- hosts: | ||
- idp.example.com | ||
rules: | ||
- host: idp.example.com | ||
http: | ||
paths: | ||
- path: / | ||
pathType: Prefix | ||
backend: | ||
service: | ||
name: keycloak | ||
port: | ||
number: 8443 |