diff --git a/operator/README.md b/operator/README.md new file mode 100644 index 000000000..c6991c276 --- /dev/null +++ b/operator/README.md @@ -0,0 +1,14 @@ +Examples of Keycloak Operator +=================================================== + +This directory contains some examples to use the Keycloak Operator on Kubernetes and OpenShift. + +They are organized in this repository under different categories (or directories) as follows: + +| Platform | Description | +|------------|----------------------------------------------------------------------------------------------| +| kubernetes | Examples about how to operate Keycloak with the Keycloak Operator on Kubernetes environment. | +| openshift | Examples about how to operate Keycloak with the Keycloak Operator on OpenShift environments. | + +For more details about how to use them, please take a look at the [Keycloak Operator Installation](https://www.keycloak.org/operator/installation) guide, +and other Operator guides. diff --git a/operator/kubernetes/README.md b/operator/kubernetes/README.md new file mode 100644 index 000000000..c26d2c49e --- /dev/null +++ b/operator/kubernetes/README.md @@ -0,0 +1,119 @@ +kubernetes: Keycloak Operator on Kubernetes +=================================================== + +Level: Beginner +Technologies: Keycloak Operator +Summary: Operate Keycloak with Keycloak Operator on Kubernetes +Target Product: Keycloak + +What is it? +----------- + +This quickstart demonstrates how to deploy the Keycloak Operator, and operate a Keycloak instance on Kubernetes environments. + +It tries to focus on the main features provided by the Keycloak Operator, such as: deploy Keycloak instances, +and import a realm with some configuration. + +System Requirements +------------------- + +This quickstart requires to have [Minikube](https://minikube.sigs.k8s.io/docs/start/) installed, ideally with the Ingres addon enabled. + +Starting Minikube +------------------- + +To start minikube: + +```shell +minikube start +``` + +To check if you have the Ingress addon enabled, enter the following command: + +```shell +minikube addons list +``` + +If the Ingress addon is not enabled, enter the following command to enable it: + +```shell +minikube addons enable ingress +``` + +Deploying Keycloak Operator +------------------- + +You can install the Operator on Kubernetes by using `kubectl` commands: + +```shell +kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/22.0.3/kubernetes/keycloaks.k8s.keycloak.org-v1.yml +kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/22.0.3/kubernetes/keycloakrealmimports.k8s.keycloak.org-v1.yml +kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/22.0.3/kubernetes/kubernetes.yml +``` + +Deploying PostgreSQL Database +------------------- + +The Keycloak Operator does not deploy any database, so it is needed to have one before operate any Keycloak instance. + +To deploy a sample PostgreSQL Database execute the command: + +```shell +kubectl apply -f postgres-db-statefulset.yaml +``` + +The following command creates a secret with the database credentials. This secret will be used later by the Keycloak instance +to establish the connection to the database instance. + +```shell +kubectl create secret generic keycloak-db-secret --from-literal=username=admin --from-literal=password=password +``` + +Deploying Keycloak +------------------- + +The Keycloak instance is described using the `Keycloak` CRD. The [example-kc.yaml](./example-kc.yaml) file represents our +instance to be managed by the Keycloak Operator. This instance will disable the hostname and TLS certificates, just only +for this testing purposes, in production environments will require to verify them. + +```shell +kubectl apply -f example-kc.yaml +``` + +Importing a new Realm +------------------- + +Creating a new Realm, and its configuration, uses the `KeycloalRealmImport` CRD. The [my-realm-kc.yaml](my-realm-kc.yaml) file +describes a sample realm. Applying it on Kubernetes with the next command: + +```shell +kubectl apply -f example-realm-kc.yaml +``` + +Accessing the Admin Console +------------------- + +The Keycloak Operator will create a secret with the initial credentials of the `admin` user. These credentials are needed to +access to the Admin Console. To extract the values of these secret: + +```shell +kubectl get secret example-kc-initial-admin -o jsonpath='{.data.password}' | base64 --decode +``` + +The following command will show the ingress created to access the Web console: + +```shell +echo http://$(kubectl get ingress example-kc-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}') +``` + +Using the right credentials from the `example-kc-initial-admin` secret, the Keycloak instance will show the `master`, and `example-realm` realms. +The `example-realm` will have some data already created, such as, the users. + +![Users of Example Realm](./example-realm-users.png) + +References +-------------------- + +* [Keycloak Operator Installation](https://www.keycloak.org/operator/installation) +* [Basic Keycloak deployment](https://www.keycloak.org/operator/basic-deployment) +* [Keycloak Realm Import](https://www.keycloak.org/operator/realm-import) diff --git a/operator/kubernetes/example-kc.yaml b/operator/kubernetes/example-kc.yaml new file mode 100644 index 000000000..c59fc244c --- /dev/null +++ b/operator/kubernetes/example-kc.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: k8s.keycloak.org/v2alpha1 +kind: Keycloak +metadata: + name: example-kc +spec: + instances: 1 + db: + vendor: postgres + host: postgres-db + usernameSecret: + name: keycloak-db-secret + key: username + passwordSecret: + name: keycloak-db-secret + key: password + poolInitialSize: 1 + poolMinSize: 1 + poolMaxSize: 10 + http: + # Disabling hostname and TLS verifications + httpEnabled: true + ingress: + enabled: true + hostname: + # Disabling hostname and TLS verifications + strict: false + strictBackchannel: false diff --git a/operator/kubernetes/example-realm-kc.yaml b/operator/kubernetes/example-realm-kc.yaml new file mode 100644 index 000000000..f3d61019b --- /dev/null +++ b/operator/kubernetes/example-realm-kc.yaml @@ -0,0 +1,43 @@ +--- +apiVersion: k8s.keycloak.org/v2alpha1 +kind: KeycloakRealmImport +metadata: + name: example-realm-kc +spec: + keycloakCRName: example-kc + realm: + id: example-realm + realm: example-realm + displayName: Example Realm + enabled: true + users: + - username: admin + credentials: + - type: password + value: password + email: admin@keycloak.org + enabled: true + realmRoles: + - admin + - user + - username: user + credentials: + - type: password + value: user + email: user@keycloak.org + enabled: true + realmRoles: + - user + - username: client + credentials: + - type: password + value: creator + email: client@keycloak.org + enabled: true + clientRoles: + account: + - "manage-account" + realm-management: + - "create-client" + - "manage-realm" + - "manage-clients" diff --git a/operator/kubernetes/example-realm-users.png b/operator/kubernetes/example-realm-users.png new file mode 100644 index 000000000..6823c590e Binary files /dev/null and b/operator/kubernetes/example-realm-users.png differ diff --git a/operator/kubernetes/postgres-db-statefulset.yaml b/operator/kubernetes/postgres-db-statefulset.yaml new file mode 100644 index 000000000..3b2bb1803 --- /dev/null +++ b/operator/kubernetes/postgres-db-statefulset.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: postgresql-db +spec: + serviceName: postgresql-db-service + selector: + matchLabels: + app: postgresql-db + replicas: 1 + template: + metadata: + labels: + app: postgresql-db + spec: + containers: + - name: postgresql-db + image: postgres:latest + volumeMounts: + - mountPath: /data + name: cache-volume + env: + - name: POSTGRES_USER + value: admin + - name: POSTGRES_PASSWORD + value: password + - name: PGDATA + value: /data/pgdata + - name: POSTGRES_DB + value: keycloak + volumes: + - name: cache-volume + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: postgres-db +spec: + selector: + app: postgresql-db + type: LoadBalancer + ports: + - port: 5432 + targetPort: 5432 diff --git a/operator/openshift/README.md b/operator/openshift/README.md new file mode 100644 index 000000000..607f02e90 --- /dev/null +++ b/operator/openshift/README.md @@ -0,0 +1,135 @@ +openshift: Keycloak Operator on OpenShift +=================================================== + +Level: Beginner +Technologies: Keycloak Operator +Summary: Operate Keycloak with Keycloak Operator on OpenShift +Target Product: Keycloak + +What is it? +----------- + +This quickstart demonstrates how to deploy the Keycloak Operator, and operate a Keycloak instance on OpenShift environments. + +It tries to focus on the main features provided by the Keycloak Operator, such as: deploy Keycloak instances, +and import a realm with some configuration. + +System Requirements +------------------- + +This quickstart requires to have [CRC](https://crc.dev/crc/getting_started/getting_started/introducing/) installed. + +Starting CRC +------------------- + +To start minikube: + +```shell +crc start +``` + +And create a sample project: + +```shell +oc new-project keycloak-quickstart +``` + +Deploying Keycloak Operator +------------------- + +CRC includes the Operator Lifecycle Manager (OLM), that it is the recommended way to install the Keycloak Operator. + +Installing operators using OLM requires to have a user with `cluster-admin` role. This role can be granted in CRC with +the following command: + +```shell +oc adm policy add-cluster-role-to-user cluster-admin developer +``` + +The Keycloak Operator can be installed using the OpenShift Web Console, or create a `Subscription` with the next command: + +```shell +oc apply -f keycloak-operator-subscription.yaml +``` + +Deploying PostgreSQL Database +------------------- + +The Keycloak Operator does not deploy any database, so it is needed to have one before operate any Keycloak instance. + +To deploy a sample PostgreSQL Database execute the command: + +```shell +kubectl apply -f postgres-db-statefulset.yaml +``` + +The following command creates a secret with the database credentials. This secret will be used later by the Keycloak instance +to establish the connection to the database instance. + +```shell +kubectl create secret generic keycloak-db-secret --from-literal=username=admin --from-literal=password=password +``` + +Creating Hostname and TLS Certificate +------------------- + +For a production ready installation, you need a hostname that can be used to contact Keycloak. See [Configuring the hostname](https://www.keycloak.org/server/hostname) +for the available configurations. + +For development purposes, this guide will use `example-kc.apps-crc.testing`. + +For development purposes, you can enter this command to obtain a self-signed certificate: + +```shell +openssl req -subj '/CN=example-kc.apps-crc.testing/O=Test Keycloak./C=US' -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem +``` +You should install it in the cluster namespace as a Secret by entering this command: + +```shell +oc create secret tls example-kc-tls-secret --cert certificate.pem --key key.pem +``` + +Deploying Keycloak +------------------- + +The Keycloak instance is described using the `Keycloak` CRD. The [example-kc.yaml](./example-kc.yaml) file represents our +instance to be managed by the Keycloak Operator. This instance will disable the hostname and TLS certificates, just only +for this testing purposes, in production environments will require to verify them. + +```shell +kubectl apply -f example-kc.yaml +``` + +Importing a new Realm +------------------- + +Creating a new Realm, and its configuration, uses the `KeycloalRealmImport` CRD. The [my-realm-kc.yaml](my-realm-kc.yaml) file +describes a sample realm. Applying it on Kubernetes with the next command: + +```shell +kubectl apply -f example-realm-kc.yaml +``` + +Accessing the Admin Console +------------------- + +The Keycloak Operator will create a secret with the initial credentials of the `admin` user. These credentials are needed to +access to the Admin Console. To extract the values of these secret: + +```shell +kubectl get secret example-kc-initial-admin -o jsonpath='{.data.password}' | base64 --decode +``` + +Open a browser and navigate to `example-kc.apps-crc.testing` and introduce the credentials to log in to Keycloak + +Using the right credentials from the `example-kc-initial-admin` secret, the Keycloak instance will show the `master`, and `example-realm` realms. +The `example-realm` will have some data already created, such as, the users. + +![Users of Example Realm](./example-realm-users.png) + +References +-------------------- + +* [Keycloak Operator Installation](https://www.keycloak.org/operator/installation) +* [Basic Keycloak deployment](https://www.keycloak.org/operator/basic-deployment) +* [Keycloak Realm Import](https://www.keycloak.org/operator/realm-import) diff --git a/operator/openshift/example-kc.yaml b/operator/openshift/example-kc.yaml new file mode 100644 index 000000000..ef325c5b6 --- /dev/null +++ b/operator/openshift/example-kc.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: k8s.keycloak.org/v2alpha1 +kind: Keycloak +metadata: + name: example-kc +spec: + instances: 1 + db: + vendor: postgres + host: postgres-db + usernameSecret: + name: keycloak-db-secret + key: username + passwordSecret: + name: keycloak-db-secret + key: password + poolInitialSize: 1 + poolMinSize: 1 + poolMaxSize: 10 + http: + tlsSecret: example-kc-tls-secret + ingress: + enabled: true + hostname: + hostname: example-kc.apps-crc.testing diff --git a/operator/openshift/example-realm-kc.yaml b/operator/openshift/example-realm-kc.yaml new file mode 100644 index 000000000..f3d61019b --- /dev/null +++ b/operator/openshift/example-realm-kc.yaml @@ -0,0 +1,43 @@ +--- +apiVersion: k8s.keycloak.org/v2alpha1 +kind: KeycloakRealmImport +metadata: + name: example-realm-kc +spec: + keycloakCRName: example-kc + realm: + id: example-realm + realm: example-realm + displayName: Example Realm + enabled: true + users: + - username: admin + credentials: + - type: password + value: password + email: admin@keycloak.org + enabled: true + realmRoles: + - admin + - user + - username: user + credentials: + - type: password + value: user + email: user@keycloak.org + enabled: true + realmRoles: + - user + - username: client + credentials: + - type: password + value: creator + email: client@keycloak.org + enabled: true + clientRoles: + account: + - "manage-account" + realm-management: + - "create-client" + - "manage-realm" + - "manage-clients" diff --git a/operator/openshift/example-realm-users.png b/operator/openshift/example-realm-users.png new file mode 100644 index 000000000..6823c590e Binary files /dev/null and b/operator/openshift/example-realm-users.png differ diff --git a/operator/openshift/keycloak-operator-subscription.yaml b/operator/openshift/keycloak-operator-subscription.yaml new file mode 100644 index 000000000..393ef7404 --- /dev/null +++ b/operator/openshift/keycloak-operator-subscription.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: keycloak-quickstart-og +spec: + targetNamespaces: + - keycloak-quickstart +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: amq-streams +spec: + channel: fast + installPlanApproval: Automatic + name: keycloak-operator + source: community-operators + sourceNamespace: openshift-marketplace + startingCSV: keycloak-operator.v22.0.3 diff --git a/operator/openshift/postgres-db-statefulset.yaml b/operator/openshift/postgres-db-statefulset.yaml new file mode 100644 index 000000000..3b2bb1803 --- /dev/null +++ b/operator/openshift/postgres-db-statefulset.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: postgresql-db +spec: + serviceName: postgresql-db-service + selector: + matchLabels: + app: postgresql-db + replicas: 1 + template: + metadata: + labels: + app: postgresql-db + spec: + containers: + - name: postgresql-db + image: postgres:latest + volumeMounts: + - mountPath: /data + name: cache-volume + env: + - name: POSTGRES_USER + value: admin + - name: POSTGRES_PASSWORD + value: password + - name: PGDATA + value: /data/pgdata + - name: POSTGRES_DB + value: keycloak + volumes: + - name: cache-volume + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: postgres-db +spec: + selector: + app: postgresql-db + type: LoadBalancer + ports: + - port: 5432 + targetPort: 5432