在docker模式下apollo portal接入自建keycloak实现单点登录

apollo portal docker部署

拉取docker镜像

docker pull apolloconfig/apollo-portal

创建挂载目录

新建文件夹用于存放配置文件和日志

mkdir -p apollo-portal/config
mkdir -p apollo-portal/logs

修改配置文件

在config目录下新建三个配置文件

  1. apollo-env.properties,将下面的地址换成你自己的各环境apollo config服务地址

dev.meta=http://fill-in-dev-meta-server:8080
fat.meta=http://fill-in-fat-meta-server:8080
uat.meta=http://fill-in-uat-meta-server:8080
pro.meta=http://fill-in-pro-meta-server:8080

注:后期如果需要增减环境,除了需要修改这个配置文件之外,还需要在管理页面,系统参数,PortalDB配置管理里将apollo.portal.envs的值改为你需要的环境列表,改完后重启portal服务才能生效

  1. application-github.properties
# DataSource
spring.datasource.url = jdbc:mysql://192.168.50.80:3306/ApolloPortalDB?characterEncoding=utf8
spring.datasource.username = dbUsername
spring.datasource.password = dbPassword
  1. application-oidc.yml
server:
  # 解析反向代理请求头
  forward-headers-strategy: framework
spring:
  security:
    oauth2:
      client:
        provider:
          # provider-name 是 oidc 提供者的名称, 任意字符均可,我这里是keycloak, registration 的配置需要用到这个名称
          keycloak:
            # 必须是 https, oidc 的 issuer-uri
            # 例如 你的 issuer-uri 是 https://host:port/auth/realms/apollo/.well-known/openid-configuration, 那么此处只需要配置 https://host:port/auth/realms/apollo 即可, spring boot 处理的时候会加上 /.well-known/openid-configuration 的后缀
            issuer-uri: https://keycloak.domain.com/realms/starcloud
        registration:
          # registration-name 是 oidc 客户端的名称, 任意字符均可, oidc 登录必须配置一个 authorization_code 类型的 registration
          keycloak:
            # oidc 登录必须配置一个 authorization_code 类型的 registration
            authorization-grant-type: authorization_code
            client-authentication-method: basic
            # client-id 是在 oidc 提供者处配置的客户端ID, 用于登录 provider
            client-id: apollo-portal
            # provider 的名称, 需要和上面配置的 provider 名称保持一致
            provider: keycloak
            # openid 为 oidc 登录的必须 scope, 此处可以添加其它自定义的 scope
            scope:
              - openid
            # client-secret 是在 oidc 提供者处配置的客户端密码, 用于登录 provider
            # 从安全角度考虑更推荐使用环境变量来配置, 环境变量的命名规则为: 将配置项的 key 当中的 点(.)、横杠(-)替换为下划线(_), 然后将所有字母改为大写, spring boot 会自动处理符合此规则的环境变量
            # 例如 spring.security.oauth2.client.registration.<fill-in-the-registration-name-here>.client-secret -> SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_<FILL_IN_THE_REGISTRATION_NAME_HERE>_CLIENT_SECRET (<FILL_IN_THE_REGISTRATION_NAME_HERE> 可以替换为自定义的 oidc 客户端的名称)
            client-secret: d43c91c0-xxxx-xxxx-xxxx-xxxxxxxxxxxx

启动docker容器

记得在环境变量里指定java opts,指定spring.profiles.active为github,oidc上面的配置才能生效

docker run\
  -d\
  --name='apollo_portal'\
  --net='br0'\
  --ip='192.168.50.68'\
  -e 'JAVA_OPTS'='-Dspring.profiles.active=github,oidc'\
  -v '/mnt/user/appdata/apollo-portal/config/':'/apollo-portal/config':'rw'\
  -v '/mnt/user/appdata/apollo-portal/logs/':'/logs':'rw' 'apolloconfig/apollo-portal'

命令执行执行后发现容器启动失败,看日志输出有下面的异常

...
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:451)
        ... 80 common frames omitted

很明显是证书问题,因为我的keycloak服务( 这是搭建过程 )使用的是自签名证书,显然是不被信任的。 java程序想要信任自签名证书的一个方法是在jdk的信任keystore里将自己的证书加入进去,apollo portal镜像使用的是openjdk镜像,这个受信任的keystore是/usr/local/openjdk-8/lib/security/cacerts文件,所以这里需要对官方镜像做一些改动。

获取keycloak tls证书

我的keycloak服务使用的是keytool生成的keystore文件作为tls加密凭证的( 详情 ),所以需要通过keystore文件生成证书,并写入到镜像的jdk keystore里

#下面这个文件夹是keycloak keystore所在文件夹
cd /mnt/user/appdata/keycloak/conf
#根据keystore生成证书文件
keytool -exportcert -keystore keystore.jks -alias keycloak -file keycloak.cer

将证书写入镜像jdk keystore

编写dockerfile制作镜像

FROM apolloconfig/apollo-portal
WORKDIR /apollo-portal
#将keycloak的证书拷贝到镜像里
COPY keycloak.cer .
#利用keytool 将自签名证书放到jdk keystore里
RUN keytool -import -trustcacerts -keystore /usr/local/openjdk-8/lib/security/cacerts -alias keycloak -file keycloak.cer -storepass changeit -noprompt

编译成镜像并启动容器

docker build -t apollo/portal .
docker run\
  -d\
  --name='apollo_portal'\
  --net='br0'\
  --ip='192.168.50.68'\
  -e 'JAVA_OPTS'='-Dspring.profiles.active=github,oidc'\
  -v '/mnt/user/appdata/apollo-portal/config/':'/apollo-portal/config':'rw'\
  -v '/mnt/user/appdata/apollo-portal/logs/':'/logs':'rw' 'apollo/portal'

这次成功启动。访问portal也成功跳转到keycloak单点登录页面,用keycloak里面已经创建好的用户成功登录了portal。但现在有个问题就是通过keycloak登录的用户 是普通用户,无法对portal进行系统管理。解决方法有两种:

  1. 在docker启动命令里暂时移除oidc配置,启动后使用之前的管理用户(默认是apollo)登录系统,然后指定通过SSO登录的用户为新的管理员。
  2. 直接修改portal数据库:
UPDATE
    `ApolloPortalDB`.`ServerConfig`
SET
    `Value` = '8a0aca75-7e0e-4ec3-b360-23b21f009b67' 
WHERE
        `Key` = 'superAdmin';

本人使用的是第二种方法,但改完数据库后重新登录没有立即生效,重启了一下portal服务才生效