コンテナレジストリーのユーザー認証にKeycloakを使用する方法

## 1. はじめに

下記のブログを参考に、Keycloakを使ってRegistryの認証を行う手順を確認したので、その内容を記載

https://rheb.hatenablog.com/entry/podman-mw-keycloak-2

## 2. 構成概要

![env.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/f68498f2-b924-476f-868e-e29f757f309d.png)

## 3. 手順詳細

### 3.1. OSインストール

ISOをDLしてCentOS Stream 9をインストールする

https://www.centos.org/download/

### 3.2. podman composeのインストール

CentOSはpodmanがインストールされているため、dockerではなくpodmanを使用する
構築時にdocker-composeファイルを使うため、事前にpodman composeをインストールする

```shell
$ sudo dnf install python-pip
$ pip install podman-compose
```

### 3.3. 名前解決

KeycloakとRegistryのFQDNをホストファイルに登録する

```
$ cat /etc/hosts
192.168.1.100   keycloak.lab.internal
192.168.1.100   registry.lab.internal
```

### 3.4. Firewall設定

以下のポートを開放する

- Keycloak: 8443/tcp
- Registry: 5000/tcp

```shell
$ sudo firewall-cmd --add-port 8443/tcp --permanent
$ sudo firewall-cmd --add-port 5000/tcp --permanent
$ sudo firewall-cmd --reload
```

### 3.5. 証明書作成

ルート認証局を作成する

```shell
$ mkdir -p ./certs
$ openssl req -x509 -newkey rsa:4096 -nodes -keyout ./certs/rootCA.key -out ./certs/rootCA.crt -days 365 -subj "/CN=RootCA"
```

KeycloakとRegistryのCSRを生成する

```shell
## Keycloak CSR
$ openssl req -new -newkey rsa:4096 -nodes -keyout ./certs/keycloak.key -out ./certs/keycloak.csr -subj "/CN=keycloak.lab.internal" -addext "subjectAltName = DNS:keycloak.lab.internal,IP:192.168.1.100"

## Registry CSR
$ openssl req -new -newkey rsa:4096 -nodes -keyout ./certs/registry.key -out ./certs/registry.csr -subj "/CN=registry.lab.internal" -addext "subjectAltName = DNS:registry.lab.internal,IP:192.168.1.100"
```

CSRを使用して証明書を署名する

```shell
## Keycloak証明書
$ openssl x509 -req -in ./certs/keycloak.csr -CA ./certs/rootCA.crt -CAkey ./certs/rootCA.key -CAcreateserial -out ./certs/keycloak.crt -days 365 -extfile <(printf "subjectAltName = DNS:keycloak.lab.internal,IP:192.168.1.100")

## Registry証明書
$ openssl x509 -req -in ./certs/registry.csr -CA ./certs/rootCA.crt -CAkey ./certs/rootCA.key -CAcreateserial -out ./certs/registry.crt -days 365 -extfile <(printf "subjectAltName = DNS:registry.lab.internal,IP:192.168.1.100")
```

### 3.6. Keycloak構築

Keycloak用ディレクトリを作成する

```shell
$ mkdir -p keycloak/certs
$ cd keycloak
```

Keycloakで使用する証明書を配置する

```shell
$ cp ../certs/keycloak.crt ./certs/
$ cp ../certs/keycloak.key ./certs/
$ chmod 644 ./certs/keycloak.key
```

docker-composeファイルを作成し、keycloakを起動する

```shell
$ vi docker-compose.yaml
$ podman compose up -d 
```
<details><summary>docker-compose.yaml</summary>

```yaml
version: '3'
services:
  keycloak:
    image: quay.io/keycloak/keycloak:26.1.3
    container_name: keycloak
    ports:
      # - "8080:8080"
      - "8443:8443"
    environment:
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
      KC_FEATURES: docker
      KC_HTTPS_CERTIFICATE_FILE: /etc/x509/https/tls.crt
      KC_HTTPS_CERTIFICATE_KEY_FILE: /etc/x509/https/tls.key
    volumes:
      - ./certs/keycloak.crt:/etc/x509/https/tls.crt:z
      - ./certs/keycloak.key:/etc/x509/https/tls.key:z
    command:
      - "start-dev"
```
</details>

### 3.7. Keycloak設定

#### Keycloakログイン

ブラウザからkeycloakにログインする

- URL: https://keycloak.lab.internal:8443
- Username: admin - docker-compose.yamlの`KEYCLOAK_ADMIN`で指定した値
- Password: admin - docker-compose.yamlの`KEYCLOAK_ADMIN_PASSWORD`で指定した値

![2025-03-18-14-41-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/0f14e82d-4673-4c13-8bd4-679496579107.png)

#### realm作成

左カラムのKeycloakプルダウンメニューから「Create realm」を押す

![2025-03-18-14-44-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/06da787c-6155-434b-b922-0f70a37395f0.png)

Realm作成画面が表示されるので、Realm情報を入力し、「Create」を押す
- Realm name: registry

![2025-03-18-14-46-32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/d749b472-9e21-4020-9b87-4389d04f085c.png)

#### Client作成

左カラムの「Clients」メニューを選択し、「Clients list」-「Create client」を押す

![2025-03-18-14-46-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/1d0f3572-ef35-4201-bc2e-2f62c8cce804.png)

Client作成画面が表示されるので、Client情報を入力し、「Next」を押す
- Client type: docker-v2
- Client ID: docker-auth

 ![2025-03-18-14-47-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/eb878d08-f036-4154-816a-d093e8e4441a.png)

「Capability config」ページはデフォルトのまま「Next」を押す
「Login settings」ページはデフォルトのまま「Save」する


#### User作成

左カラムの「Users」メニューを選択し、「User list」-「Create new user」を押す

![2025-03-18-14-49-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/d9bd7001-c295-491a-8be2-598b83cc3470.png)

ユーザー情報を入力し「Create」を押す
- Username: user1
- Email: user1@lab.internal
- First name: user1
- Last name: test

![2025-03-20-15-03-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/fc3cd32f-9f69-4707-aec9-f98fcb960207.png)

「User datails」画面から「Credentials」タブを選択し、「Set password」選択する

![2025-03-18-14-50-46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/c8b6160b-3726-4bcd-8d2e-94c3c967dda1.png)

パスワード情報を入力し、「Save」を押す
- Password: password
- Temporary: Off

![2025-03-18-14-51-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/ae9a82b6-e2a1-40df-9e36-e9334cc56861.png)


#### Certificateファイルを取得する

左カラムの「Realm Settings」メニューを選択し、「Keys」タブ内の「Keys list」にあるRS256の「Certificate」を押す

![2025-03-18-15-01-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692186/68e4dcff-478e-4f48-aa8a-787890faa126.png)


表示された内容をコピーしてpemファイルを作成する

```shell
$ cat certs/keycloak-cert.pem
-----BEGIN CERTIFICATE-----
MIICnzCCAYcCBgGVsbxOmTANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhyZWdp
...<snip>...
HEhtJLHk2PKoMCMDSm8wCxe/i1WajzZd96k8//s8mnY2j1cUON0CQelcS4RHhYIZ
LUFo
-----END CERTIFICATE-----
```

### 3.8. Registry構築

Registry用ディレクトリを作成する

```shell
$ cd ../
$ mkdir -p registry/{certs,data}
$ cd registry
```

Registryで使用する証明書を配置する

```shell
$ cp ../certs/registry.crt certs/
$ cp ../certs/registry.key certs/
$ cp ../certs/keycloak-cert.pem certs/
```

docker-composeファイルを作成し、Registryを起動する

```shell
$ vi docker-compose.yaml
$ podman compose up -d
```

<details><summary>docker-compose.yaml</summary>

```yaml
version: '3'
services:
  registry:
    image: registry:2
    container_name: registry
    ports:
      - 5000:5000
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
      REGISTRY_HTTP_TLS_CERTIFICATE: /certs/registry.crt
      REGISTRY_HTTP_TLS_KEY: /certs/registry.key
      REGISTRY_AUTH_TOKEN_REALM: https://keycloak.lab.internal:8443/realms/registry/protocol/docker-v2/auth
      REGISTRY_AUTH_TOKEN_SERVICE: docker-auth
      REGISTRY_AUTH_TOKEN_ISSUER: https://keycloak.lab.internal:8443/realms/registry
      REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE: /certs/keycloak-cert.pem
    volumes:
      - ./data:/data:z
      - ./certs:/certs:z
```
</details>

### 3.9. 動作確認

作成したルート証明書を信頼リストに追加する

```shell
sudo cp ./certs/rootCA.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
```

podman login確認

```shell
$ podman login registry.lab.internal:5000
Username: user1
Password:
Login Succeeded!
```

imageのpush確認

```shell
$ podman pull docker.io/library/nginx:latest
$ podman tag docker.io/library/nginx:latest registry.lab.internal:5000/nginx:latest
$ podman push registry.lab.internal:5000/nginx:latest
Getting image source signatures
Copying blob 1287fbecdfcc done   |
Copying blob d26dc06ef910 done   |
Copying blob d98dcc720ae0 done   |
Copying blob aa82c57cd9fe done   |
Copying blob ad2f08e39a9d done   |
Copying blob 135f786ad046 done   |
Copying blob 03d9365bc5dc done   |
Copying config 53a18edff8 done   |
Writing manifest to image destination
```