基于 kubernetes 部署 Keycloak 并集成 Harbor 实现统一身份认证

一、keycloak概述

Keycloak 是一款开源的身份和访问管理(IAM)工具,支持多种协议,包括 OIDC(OpenID Connect)、OAuth 2.0、SAML 等。它简化了身份认证与授权流程,提供了集中管理用户、角色、权限等功能,常被用作企业或微服务体系下的统一认证中心。

二、Keycloak中的相关概念

在这里插入图片描述

  • keycloak
    实现身份与访问的一整套解决方案。具体而言,它是搭建在某台服务器上的一个服务实例,可以通过管理控制台进行管理和配置。

  • realm 领域
    领域是keycloak中专门用来管理项目的工作区,每个Keycloak实例可以包含一个或多个领域,每个领域是一个独立的安全域,不同领域之间的资源相互隔离。领域分为两类,一类是master领域,由Keycloak刚启动时创建,用于管理admin账号以及创建其他的领域;另一类是用户自己创建的普通领域,用于管理具体的项目和用户。

  • client 客户端
    客户端在领域中创建,一个领域可以创建多个客户端,例如一个企业可以创建两个客户端:销售人员客户端、研发人员客户端。在具体的客户端中管理具体的应用程序。

  • application 应用程序
    一个客户端可以配置一至多个应用程序,同一客户端下的多个应用程序可以实现单点登录。一个应用程序可以是SpringBoot应用、JavaScript应用、Android应用等。

  • adapter 适配器
    适配器,用来实现客户端与Keycloak之间的集成。具体而言,同一客户端下的应用共用一个客户端适配器的配置,这也确保了单点登录的实现。

三、在k8s集群上部署keycloak

3.1 部署keycloak

1)下载官方提供的yaml文件

wget  https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/refs/heads/main/kubernetes/keycloak.yaml

2)yaml文件清单如下

root@k8s-master01:~/keycloak# cat keycloak.yaml
apiVersion: v1
kind: Service
metadata:
  name: keycloak
  labels:
    app: keycloak
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: http
      name: http
  selector:
    app: keycloak
  type: LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: keycloak
  # Used to
  name: keycloak-discovery
spec:
  selector:
    app: keycloak
  # Allow not-yet-ready Pods to be visible to ensure the forming of a cluster if Pods come up concurrently
  publishNotReadyAddresses: true
  clusterIP: None
  type: ClusterIP
---
apiVersion: apps/v1
# Use a stateful setup to ensure that for a rolling update Pods are restarted with a rolling strategy one-by-one.
# This prevents losing in-memory information stored redundantly in two Pods.
kind: StatefulSet
metadata:
  name: keycloak
  labels:
    app: keycloak
spec:
  serviceName: keycloak-discovery
  # Run with one replica to save resources, or with two replicas to allow for rolling updates for configuration changes
  replicas: 1
  selector:
    matchLabels:
      app: keycloak
  template:
    metadata:
      labels:
        app: keycloak
    spec:
      containers:
        - name: keycloak
          image: quay.io/keycloak/keycloak:26.3.2
          args: ["start"]
          env:
            - name: KC_BOOTSTRAP_ADMIN_USERNAME
              value: "admin"
            - name: KC_BOOTSTRAP_ADMIN_PASSWORD
              value: "admin"
            # In a production environment, add a TLS certificate to Keycloak to either end-to-end encrypt the traffic between
            # the client or Keycloak, or to encrypt the traffic between your proxy and Keycloak.
            # Respect the proxy headers forwarded by the reverse proxy
            # In a production environment, verify which proxy type you are using, and restrict access to Keycloak
            # from other sources than your proxy if you continue to use proxy headers.
            - name: KC_PROXY_HEADERS
              value: "xforwarded"
            - name: KC_HTTP_ENABLED
              value: "true"
            # In this explorative setup, no strict hostname is set.
            # For production environments, set a hostname for a secure setup.
            - name: KC_HOSTNAME_STRICT
              value: "false"
            - name: KC_HEALTH_ENABLED
              value: "true"
            - name: 'KC_CACHE'
              value: 'ispn'
            # Use the Kubernetes configuration for distributed caches which is based on DNS
            - name: 'KC_CACHE_STACK'
              value: 'kubernetes'
            # Passing the Pod's IP primary address to the JGroups clustering as this is required in IPv6 only setups
            - name: POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
            # Instruct JGroups which DNS hostname to use to discover other Keycloak nodes
            # Needs to be unique for each Keycloak cluster
            - name: JAVA_OPTS_APPEND
              value: '-Djgroups.dns.query="keycloak-discovery" -Djgroups.bind.address=$(POD_IP)'
            - name: 'KC_DB_URL_DATABASE'
              value: 'keycloak'
            - name: 'KC_DB_URL_HOST'
              value: 'postgres'
            - name: 'KC_DB'
              value: 'postgres'
            # In a production environment, use a secret to store username and password to the database
            - name: 'KC_DB_PASSWORD'
              value: 'keycloak'
            - name: 'KC_DB_USERNAME'
              value: 'keycloak'
          ports:
            - name: http
              containerPort: 8080
          startupProbe:
            httpGet:
              path: /health/started
              port: 9000
            periodSeconds: 1
            failureThreshold: 600
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 9000
            periodSeconds: 10
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /health/live
              port: 9000
            periodSeconds: 10
            failureThreshold: 3
          resources:
            limits:
              cpu: 2000m
              memory: 2000Mi
            requests:
              cpu: 500m
              memory: 1700Mi
---
# This is deployment of PostgreSQL with an ephemeral storage for testing: Once the Pod stops, the data is lost.
# For a production setup, replace it with a database setup that persists your data.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
  labels:
    app: postgres
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: mirror.gcr.io/postgres:17
          env:
            - name: POSTGRES_USER
              value: "keycloak"
            - name: POSTGRES_PASSWORD
              value: "keycloak"
            - name: POSTGRES_DB
              value: "keycloak"
            - name: POSTGRES_LOG_STATEMENT
              value: "all"
          ports:
            - name: postgres
              containerPort: 5432
          volumeMounts:
            # Using volume mount for PostgreSQL's data folder as it is otherwise not writable
            - name: postgres-data
              mountPath: /var/lib/postgresql
      volumes:
        - name: postgres-data
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: postgres
  name: postgres
spec:
  selector:
    app: postgres
  ports:
    - protocol: TCP
      port: 5432
      targetPort: 5432
  type: ClusterIP

3)部署keycloak

kubectl apply -f ingress.yaml --namespace keycloak

4)查看部署详情

root@k8s-master01:~/keycloak# kubectl get pod -n keycloak
NAME                       READY   STATUS    RESTARTS   AGE
keycloak-0                 1/1     Running   0          5h55m
postgres-d4d4f5d96-5qhmh   1/1     Running   0          5h55m

3.2 配置域名和证书

编写ingress的清单文件如下

root@k8s-master01:~/keycloak# cat ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: keycloak-ingress
  namespace: keycloak
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
    nginx.ingress.kubernetes.io/ssl-redirect: "true" # 强制将 HTTP 请求重定向到 HTTPS。
    cert-manager.io/cluster-issuer: my-ca-issuer     # 配置cert-manager自动申请证书
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - keycloak.xug.com
      secretName: keycloak-tls-secret
  rules:
    - host: keycloak.xug.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: keycloak
                port:
                  number: 80

PS: 关于cert-manager配置可以参考博主的另一篇文章:cert-manager 是什么?一篇文章搞懂 Kubernetes
证书自动化管理

创建ingress

root@k8s-master01:~/keycloak# kubectl apply -f ingress.yaml

等待证书生成后,就可以通过 keycloak.xug.com 访问 keycloak 了。

root@k8s-master01:~/keycloak# kubectl get certificate -n keycloak
NAME                  READY   SECRET                AGE
keycloak-tls-secret   True    keycloak-tls-secret   4h
root@k8s-master01:~/keycloak# kubectl get secret -n keycloak
NAME                  TYPE                DATA   AGE
keycloak-tls-secret   kubernetes.io/tls   3      4h

访问 keycloak.xug.com 账号密码是 admin/admin

在这里插入图片描述

四、配置 Keycloak 作为 Harbor 的身份认证和授权服务

2.1 创建Realm

创建一个新的 Realm,命名为sso

2.2 添加用户

在 sso Realm 中创建测试用户。

给用户设置密码

在这里插入图片描述

2.3 创建client

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这里写上Harbor的回调地址

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

五、Harbor对接keycloak

登录Harbor -> 导航到系统管理 -> 配置管理 -> 认证管理

填写上keycloak的认证信息 oidc endpoint、client id、client secret以及 oidc scope

在这里插入图片描述

退出登录,再重新登录Harbor,可以发现Harbor登录界面就多出了通过OIDC提供商登录

在这里插入图片描述

输入我们在keycloak sso realms中创建的用户和密码

在这里插入图片描述

如果我们是第一次通过OIDC登录Harbor,需要创建一个Harbor用户和keycloak用户进行绑定

Harbor 与 Keycloak 的用户绑定,本质是通过 OIDC 协议传递的 sub 唯一标识,在 Harbor 内部建立 “外部用户 ID(Keycloak sub)- 内部用户 ID(Harbor user_id)” 的映射关系。这一机制解决了两套独立用户体系的协同问题,既利用了 Keycloak 强大的身份认证能力,又保留了 Harbor 对用户权限的精细化管理,是企业级身份集成的核心技术支撑。

在这里插入图片描述

在这里插入图片描述

六、总结

本文介绍了如何在 Kubernetes 中部署 Keycloak,并将其作为统一登录系统与 Harbor 集成。

通过简单的配置,我们实现了使用 Keycloak 账号登录 Harbor 的功能,提升了账号管理和访问安全。Keycloak 支持多种协议,易于扩展,非常适合在云原生环境中作为统一的身份认证中心。

部署完成后,用户只需记住一套账号密码,即可安全访问多个系统,真正实现了单点登录(SSO)的便利。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋刀鱼什么味_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值