2023-12-12 11:36:52 +01:00

456 lines
14 KiB
ReStructuredText
Executable File

.. meta::
:description: add a SEO description here
:keywords: add SEO keywords here, and list additionally all OTC services used
===========================================
Identity Federation through Keycloak/GitHub
===========================================
.. Overview
Overview
========
| > *There are no further requirements for an article except to include the following sections at the **end**, and to follow all general Open Telekom Architecture Center content requirements.*
| > *An Open Telekom Cloud Architecture Center article template, for **external** creators, requires the following sections at the end of the article:*
.. topic:: TL;DR
| >> Make a brief summary of what is the article about
.. Main Article
.. Components
| > *No header required here*
| > *(Expected to list all the Open Telekom Cloud components used, but it could be optional if it just an architectural paradigm.*
.. Sections 1..n
| > *You can name the Section titles as it seems fit to the workflow of the article.*
Create a VPC and a Subnet
=========================
We are going to need a Virtual Private Cloud (VPC) and at least one Subnet where we are going
to provision both RDS instances and CCE nodes. For enhanced security granularity, we could split
those resources in two different Subnets.
.. image:: /_static/images/SCR-20231208-ezg.png
.. warning:: RDS and CCE nodes have to be on the same VPC.
Deploy a PostgreSQL with RDS
============================
Keycloak, as a stateful workload, requires the presence of a persistent storage in order to
maintain its data and configuration during pod restarts. We could deploy a PostgreSQL database
as a CCE workload, but this would require additional administrative overhead from your side.
The Managed Relational Database Service of Open Telekom Cloud is a perfect fit for this scenario.
A scalable turn-key solution, that fully integrated with the rest of managed services of the platform
without demanding from the consumer additional administrative effort.
Create Security Groups
++++++++++++++++++++++
We are going to need two different Security Groups. One for the RDS nodes, so it can accept client calls
on port ``5432`` (Inbound Rules), which they only reside in the same Subnet (in case we went for a single Subnet solution):
.. image:: /_static/images/SCR-20231208-fh3.png
|
And one Security Group for the client nodes that need to access the database (Outbound Rules), in our case those would
be the CCE nodes where Keycloak is going to be installed on.
.. image:: /_static/images/SCR-20231208-k2x.png
Provision a Database
++++++++++++++++++++
Now as next, we need to provision a PostgreSQL 14 database. Pick the instance and storage class size that fit your needs:
.. image:: /_static/images/SCR-20231208-k8t.png
|
and make sure that you:
- you place the RDS nodes in the same VPC with the CCE nodes
- assign ``rds-instances`` as the Security Group for the RDS nodes
.. image:: /_static/images/SCR-20231208-ka7.png
Create a Private DNS Zone
+++++++++++++++++++++++++
We are provisioning PostgreSQL in order to support the functionality of Keycloak. For that matter, although Open Telekom
Cloud employs this RDS instance with a floating IP address, it would be better that we connect the RDS instance with
Keycloak via a fully qualified domain name and let the Open Telekom Cloud's DNS service to manage the resolution of that
endpoints. In the Domain Name Service management panel click Private Zone and create a new one that points to the VPC
that CCE and RDS nodes are placed:
.. image:: /_static/images/SCR-20231211-f5u.png
|
and then click Manage Record Set to add a new **A Record** to this zone:
.. image:: /_static/images/SCR-20231211-ffb.png
|
.. note:: The domain name, will be a fictitious domain representing your solution and not a public one. It can be
virtually any domain or subdomain that conforms to the a FQDN rules.
|
The floating IP of the RDS instance can be found in the Basic Information panel of the database:
.. image:: /_static/images/SCR-20231211-fj8.png
Provision a CCE Cluster
=======================
We are going to need a CCE Cluster. In order to provision one, you can follow the configuration steps of the wizard
paying attention to the following details:
- We are not going to need an HA cluster - of course adjust to your needs because this is not something you can
change in the future.
- We need to provision the CCE Cluster in the same VPC as the RDS nodes.
- If you follow the single Subnet lab instructions make sure you place the CCE Nodes in the same Subnet that RDS nodes
reside.
|
.. image:: /_static/images/SCR-20231211-fp6.png
|
Add worker nodes to the CCE cluster using the wizard, and wait all nodes to become operational. Then add to **each** node
an additional Security Group, in particular the ``rds-client`` that we created earlier in this lab.
.. image:: /_static/images/SCR-20231211-g7y.png
.. note:: Make your own decision how you're going to access this CCE Cluster afterwards. You can assign an Elastic
IP Address and access it over the Internet or provision and additional public-facing bastion host and access
it through this machine. **We categorically recommend the latter**.
Deploy Keycloak on CCE
======================
We are going to deploy Keycloak using simple Kubernetes manifests. Deploy those YAML manifests in the order described
below using the command on your bastion host (or in any other machine if you chose to go for an EIP):
.. code-block:: yaml
kubectl apply -f <<filename.yaml>>
Deploy Keycloak Secrets
+++++++++++++++++++++++
First we are going to need a Namespace in our CCE Cluster, in order to deploy all the resources required by Keycloak:
.. code :: shell
kubectl create namespace keycloak
We are going to need two Secrets. One, ``postgres-credentials``, that will contain the credentials to access the PostgreSQL
database instance and a second one, ``keycloak-secrets``, that will contain the necessary credential to access the web
console of Keycloak:
.. code-block:: yaml
:linenos:
:emphasize-lines: 9,20
apiVersion: v1
kind: Secret
metadata:
name: postgres-credentials
namespace: keycloak
type: Opaque
stringData:
POSTGRES_USER: root
POSTGRES_PASSWORD: <<POSTGRES_PASSWORD>>
POSTGRES_DB: postgres
---
apiVersion: v1
kind: Secret
metadata:
name: keycloak-secrets
namespace: keycloak
type: Opaque
stringData:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: <<KEYCLOAK_ADMIN_PASSWORD>>
.. note:: ``POSTGRES_PASSWORD`` is the password for the ``root`` user your provided during the creation of the RDS instance.
``KEYCLOAK_ADMIN_PASSWORD``, as we mentioned before, is the password for the ``admin`` user of the Keycloak web console.
You can easily create random strong passwords, in Linux terminal, with the following command:
.. code-block:: shell
openssl rand -base64 14
Deploy Keycloak Application
+++++++++++++++++++++++++++
Next step, is deploying Keycloak itself:
.. code-block:: yaml
:linenos:
:emphasize-lines: 23,26,27,31,32,48,49,50,51,55,56,60,61
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:21.0.2
args: ["start-dev"]
env:
- name: KEYCLOAK_ADMIN
valueFrom:
secretKeyRef:
key: KEYCLOAK_ADMIN
name: keycloak-secrets
- name: KEYCLOAK_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
key: KEYCLOAK_ADMIN_PASSWORD
name: keycloak-secrets
- name: KC_PROXY
value: "edge"
- name: KC_HEALTH_ENABLED
value: "true"
- name: KC_METRICS_ENABLED
value: "true"
- name: KC_HOSTNAME_STRICT_HTTPS
value: "true"
- name: KC_LOG_LEVEL
value: INFO
- name: KC_DB
value: postgres
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: postgres-credentials
key: POSTGRES_DB
- name: KC_DB_URL
value: jdbc:postgresql://postgresql.blueprints.arc:5432/$(POSTGRES_DB)
- name: KC_DB_USERNAME
valueFrom:
secretKeyRef:
name: postgres-credentials
key: POSTGRES_USER
- name: KC_DB_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: POSTGRES_PASSWORD
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 250
periodSeconds: 10
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 500
periodSeconds: 30
resources:
limits:
memory: 512Mi
cpu: "1"
requests:
memory: 256Mi
cpu: "0.2"
As you will notice in the highlighted lines, we parameterize the credentials portion of this manifest by referencing
the variables and their values we installed in the previous step with the Secrets. Important to mention the significance
of line 51, where we connect Keycloak with the RDS instance using the FQDN we created in our Private DNS Zone for this
instance.
Deploy Keycloak Service
+++++++++++++++++++++++
We deployed the application, but at the time being is not accessible by an internal or external actor (direct access
from Pods does not count in this case). For that matter, we need to deploy a Service that will expose Keycloak's
workload:
.. code-block:: yaml
:linenos:
:emphasize-lines: 15
apiVersion: v1
kind: Service
metadata:
name: keycloak
namespace: keycloak
labels:
app: keycloak
spec:
ports:
- name: https
port: 443
targetPort: 8080
selector:
app: keycloak
type: NodePort
.. note:: Pay attention to **line 15**, where we set the ``type`` as ``NodePort``. That's because we want to expose
this service externally, in a later step, via an Ingress.
Expose Keycloak
===============
.. image:: /_static/images/SCR-20231211-di1.png
Create an Elastic Load Balancer
+++++++++++++++++++++++++++++++
First in our list for this part, is to create an Elastic Load Balancer that will be employed with the following:
- An EIP address
- Support L4 and L7 load balancing
- Be in the same VPC/Subnet as the nodes of our CCE Cluster
- Associate backend servers by using their IP addresses (*IP as Backend*)
.. image:: /_static/images/SCR-20231211-i88.png
.. note:: Note down the **ELB ID**, we are going to need it to configure the Nginx Ingress that we will deploy next.
Deploy Nginx Ingress on CCE
+++++++++++++++++++++++++++
We are going to deploy in this step the Ingress that will sit between our ELB and the Keycloak Service and expose it
in the address of our preference (keycloak.example.com for this lab)
.. warning:: Do not forget that the FQDN we are going to use to expose the Keycloak Service has to point to a **real** domain or
subdomain that you actually **own**!
We will use `Helm <https://helm.sh>`_ to deploy Nginx Ingress to our CCE Cluster. Helm is the de-facto package manager
of Kubernetes and if you don't have it already installed on your remote machine or your bastion host, you can do it with
the following commands:
.. code-block:: shell
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
We have to provide to the helm chart a couple configuration values (``overrides.yaml``), among them the internal ID
of the Elastic Load Balancer is the most important - as it will bind the future ingresses that will be created using
this ingress class with the specific load balancer.
.. code-block:: yaml
:linenos:
:emphasize-lines: 6
controller:
replicaCount: 1
service:
externalTrafficPolicy: Cluster
annotations:
kubernetes.io/elb.id: "0000000-0000-0000-0000-000000000000"
.. note:: Special attention required at **line 6**, replace the placeholder value with the ID you copied from the
main panel of your newly created Elastic Load Balancer.
We can now install the chart (it will automatically create and deploy everything in a namespace named ``nginx-system``):
.. code-block:: shell
helm upgrade --install -f overrides.yaml --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
Create a Public DNS Endpoint
++++++++++++++++++++++++++++
Create the Endpoint manually
----------------------------
Create the Endpoint with ExternalDNS
------------------------------------
Deploy ExternalDNS on CCE
`````````````````````````
Deploy a Keycloak Endpoint
``````````````````````````
Deploy Keycloak Ingress
+++++++++++++++++++++++
Section n
=========
.. Next steps & Related Resources
Next Steps
==========
| > *(Expected, but it could be optional if you don't want the article stops here and doesn't connect with other resources)*
| > *Add site-relative links to Architecture Center related articles but NOT to external or third-party resources*
| > *If there are additional resources like Cloud Topology Designer solution or Github repos, list them first with the aforementioned order*
.. seealso::
`Link1 <https://www.t-systems.com>`_
`Link2 <https://www.t-systems.com>`_
Resources
=========
.. Resources
| > *If there are additional deployable resources like Cloud Topology Designer solution or Github repos, list them first with the aformentioned order*
.. seealso::
`Link1 <https://www.t-systems.com>`_
`Link2 <https://www.t-systems.com>`_
.. References
References
==========
| > *Add site-relative links to Architecture Center articles*
| > *Add links to external or third-party resources*
.. seealso::
`Link1 <https://www.t-systems.com>`_
`Link2 <https://www.t-systems.com>`_
| > **REMOVE ALL THE LINES THAT START WITH "| >"**