389ds on Kubernetes

## はじめに
はじめに、この記事は、389 Directory Server（以下、389ds）をKubernetes上にデプロイし、動作確認する方法の紹介を目的としています。間違っている点などあればご指摘ください。

389dsは、Linux上で動作するオープンソースのディレクトリサービスです。LDAPやKerberosなどのプロトコルをサポートしており、認証やアクセス制御、ディレクトリサービスなどの用途に利用されています。

今回はローカルのminikube上で動作させていきます。
公式ではOpenshiftにデプロイするマニフェストが記載してありますが、こちらをkubernetesで動作するように修正し試していきます。イメージについては`docker.io`のイメージを利用していきます。また、動作することを目的としているのでTLS化部分も省略していきます。

## 手順
### 389dsのコンテナのデプロイ
#### 以下のマニフェストの準備を行う。
* svc-internal.yaml
```yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: dirsrv
  name: dirsrv-internal-svc
spec:
  clusterIP: None
  ports:
  - name: dirsrv-nonsecure
    port: 3390
    protocol: TCP
    targetPort: 3390
  selector:
    app: dirsrv
  type: ClusterIP
status:
  loadBalancer: {}
```
* svc-external.yaml
```yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: dirsrv
  name: dirsrv-external-svc
spec:
  ports:
  - name: dirsrv-nonsecure
    port: 3390
    protocol: TCP
    targetPort: 3390
    nodePort: 30390
  selector:
    app: dirsrv
  type: NodePort
status:
  loadBalancer: {}
```
* dirsrv-statefulset.yaml
```yaml
kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: dirsrv
spec:
  serviceName: dirsrv-internal-svc
  replicas: 1
  selector:
    matchLabels:
      app: dirsrv
  template:
    metadata:
      labels:
        app: dirsrv
    spec:
      initContainers:
      # Init container is required to change the permissions after a persistent volume is mounted.
      # Otherwise dscontainer will be denied to create subdirectories and will fail to start.
      - name: dirsrv-init-container
        image: busybox
        command: ["sh", "-c", "chown -R 389:389 /data"]
        volumeMounts:
        - name: dirsrv-data
          mountPath: /data
      containers:
        - name: dirsrv-container
          image: docker.io/389ds/dirsrv:latest
          env:
          ## Set `cn=Directory Manager`'s password
          - name: DS_DM_PASSWORD
            valueFrom:
              secretKeyRef:
                name: dirsrv-dm-password
                key: dm-password
          ## Use suffix as a basedn in `dsrc` file
          # - name: DS_SUFFIX_NAME
          #   value: "dc=example,dc=com"
          ## DS_ERRORLOG_LEVEL - set the log level for `ns-slapd`, default is 266354688
          # - name: DS_ERRORLOG_LEVEL
          #   value: "8192"
          ## DS_MEMORY_PERCENTAGE - set LDBM autotune percentage (`nsslapd-cache-autosize`), default is 25
          #- name: DS_MEMORY_PERCENTAGE
          #  value: "10"
          ## DS_REINDEX` - run database reindex task (`db2index`)
          # - name: DS_REINDEX
          #   value: "True"
          ## DS_STARTUP_TIMEOUT - set container startup timeout in seconds, default is 60 seconds.
          # - name: DS_STARTUP_TIMEOUT
          #   value: "120"
          ports:
            - containerPort: 3390
              protocol: TCP
          volumeMounts:
          - name: dirsrv-data
            mountPath: "/data"
  volumeClaimTemplates:
  - metadata:
      name: dirsrv-data 
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi

```

#### namespaceの作成
```bash
$ alias k=kubectl
$ kubectl create ns 389ds
```

#### Serviceを作成
```bash
$ k apply -f svc-internal.yaml -n 389ds
$ k apply -f svc-external.yaml -n 389ds
$ k get svc -n 389ds
```

#### Directory Managerのパスワード作成(管理者アカウント的な)
```bash
k create secret generic dirsrv-dm-password --from-literal=dm-password='Secret123' -n 389ds
```

#### 389dsのデプロイ
```bash
k apply -f dirsrv-statefulset.yaml -n 389ds
k get po -n 389ds
```
### 動作確認
現時点だとldapsearchかけてもエントリー情報がないのでバックエンドとsuffixを作成します。
```bash
$ k exec -it dirsrv-0 -n 389ds -- dsconf localhost backend create --suffix dc=example,dc=com --be-name userroot --create-suffix --create-entries

```

今回設定したコンテナイメージにはldap関連コマンドがデフォルトで入っていないため、ldap-clientを起動し、コンテナ内で`ldapsearch`コマンドを実施してみます。
```bash
$ k run ldap-client -it --image=quay.io/389ds/clients:latest -n 389ds
```

```bash
[root@ldap-client /]# ldapsearch -xLLL -H ldap://dirsrv-internal-svc.389ds.svc.cluster.local:3389 -D "cn=Directory Manager" -w Secret123
dn: dc=example,dc=com
objectClass: top
objectClass: domain
dc: example
description: dc=example,dc=com

dn: ou=groups,dc=example,dc=com
objectClass: top
objectClass: organizationalunit
ou: groups

dn: ou=people,dc=example,dc=com
objectClass: top
objectClass: organizationalunit
ou: people

dn: ou=permissions,dc=example,dc=com
objectClass: top
objectClass: organizationalunit
ou: permissions

dn: ou=services,dc=example,dc=com
objectClass: top
objectClass: organizationalunit
ou: services

dn: uid=demo_user,ou=people,dc=example,dc=com
objectClass: top
objectClass: nsPerson
objectClass: nsAccount
objectClass: nsOrgPerson
objectClass: posixAccount
uid: demo_user
cn: Demo User
displayName: Demo User
legalName: Demo User Name
uidNumber: 99998
gidNumber: 99998
homeDirectory: /var/empty
loginShell: /bin/false

dn: cn=demo_group,ou=Groups,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: posixGroup
objectClass: nsMemberOf
cn: demo_group
gidNumber: 99999

dn: cn=group_admin,ou=permissions,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: nsMemberOf
cn: group_admin

dn: cn=group_modify,ou=permissions,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: nsMemberOf
cn: group_modify

dn: cn=user_admin,ou=permissions,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: nsMemberOf
cn: user_admin

dn: cn=user_modify,ou=permissions,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: nsMemberOf
cn: user_modify

dn: cn=user_passwd_reset,ou=permissions,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: nsMemberOf
cn: user_passwd_reset

dn: cn=user_private_read,ou=permissions,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: nsMemberOf
cn: user_private_read
```
エントリー情報が取得できました。

## まとめ
本番環境で運用する上では考慮する点(冗長化や永続化、暗号化など)があると思いますが、LDAP Serverを簡単に触れる環境を作れるという点は非常に有用かなと感じました。せっかくLDAP Serverを立ち上げたので認証連携を色々試してみようかなと思います。CUIから触るのは結構面倒な点が多いので、「Apache Directory Studioを使用して389ds触ってみた」も記載しようと思います。

## 参考
https://directory.fedoraproject.org/docs/389ds/howto/howto-deploy-389ds-on-openshift.html