IK.AM

@making's tech note


Spring BootアプリをKubernetesにデプロイする際にアプリ側でTLS Terminationをするメモ

🗃 {Dev/CaaS/Kubernetes}
🏷 Spring Boot 🏷 TLS 🏷 Kubernetes 🏷 PKS 
🗓 Updated at 2019-09-29T14:08:56Z  🗓 Created at 2019-08-19T08:39:00Z   🌎 English Page

KubernetesにSpring Bootアプリを置く場合はIngressを使用するなど、前段でTLS Terminationすることが多いと思うが、 アプリ側で実施したい場合のやり方を説明する。

X-Forwaded-ProtoヘッダーがLBが正しく設定してくれず、ログイン後のリダイレクトがうまく行かない(HTTPにリダイレクトされる)ことがあったのでメモ

PKS + NSX-TでNSX-T Ingressを使うケースで発生。

Spring Boot 2.1.5で動作確認しているが、2.xであれば同じはず。

サンプルアプリとしてSpring Musicを使用する。 このアプリ自体はただのSpring Bootアプリであり、普通に8080番をlistenするHTTPアプリである。

docker runするとhttp://localhost:8080でアクセスできる。

docker run --rm -p 8080:8080 trisberg/spring-music:cnb

image

ソースコードを変更せずに、このDokcerイメージをそのまま使ってTLS Terminationしたい。

次のspring-music.ymlを作成する。ポイントはinitContainersでTLS証明書(pem形式)をjks形式に変換し、マウントしたボリュームに配置しているところ。 あとは環境変数SERVER_SSL_****を設定し、アプリ側のTLS設定を行う。

この記事の応用版

apiVersion: v1
kind: Namespace
metadata:
  name: spring-music
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-music
  namespace: spring-music
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spring-music
  template:
    metadata:
      labels:
        app: spring-music
    spec:
      initContainers:
      - image: openjdk:11-jdk-slim
        name: pem-to-keystore
        volumeMounts:
        - name: keystore-volume
          mountPath: /keystores
        - name: spring-music-tls
          mountPath: /spring-music-tls
        env:
        - name: SERVER_SSL_KEY_PASSWORD
          valueFrom:
            secretKeyRef:
              name: spring-music
              key: server.ssl.key-password
        command:          
        - sh
        - -c
        - |
          set -e
          openssl pkcs12 -export \
                  -name spring-music \
                  -in /spring-music-tls/tls.crt \
                  -inkey /spring-music-tls/tls.key \
                  -out /keystores/spring-music.p12 \
                  -password pass:foobar
          keytool -importkeystore \
                  -destkeystore /keystores/spring-music.jks \
                  -srckeystore /keystores/spring-music.p12 \
                  -deststoretype pkcs12 \
                  -srcstoretype pkcs12 \
                  -alias spring-music \
                  -deststorepass ${SERVER_SSL_KEY_PASSWORD} \
                  -destkeypass ${SERVER_SSL_KEY_PASSWORD} \
                  -srcstorepass foobar \
                  -srckeypass foobar \
                  -noprompt
      containers:
      - image: trisberg/spring-music:cnb
        name: spring-music
        ports:
        - containerPort: 8443
        volumeMounts:
        - name: keystore-volume
          mountPath: /keystores
          readOnly: true
        env:
        - name: SERVER_PORT
          value: "8443"
        - name: SERVER_SSL_ENABLED
          value: "true"
        - name: SERVER_SSL_PROTOCOL
          value: TLSv1.2
        - name: SERVER_SSL_KEY_STORE
          value: file:///keystores/spring-music.jks
        - name: SERVER_SSL_KEY_STORE_TYPE
          value: PKCS12
        - name: SERVER_SSL_KEY_ALIAS
          value: spring-music
        - name: SERVER_SSL_KEY_PASSWORD
          valueFrom:
            secretKeyRef:
              name: spring-music
              key: server.ssl.key-password
        - name: SERVER_SSL_KEY_STORE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: spring-music
              key: server.ssl.key-password
        readinessProbe:
          httpGet:
            path: /actuator/health
            port: 8443
            scheme: HTTPS
          initialDelaySeconds: 10
          timeoutSeconds: 3
          failureThreshold: 3
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /actuator/info
            port: 8443
            scheme: HTTPS
          initialDelaySeconds: 20
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 1
      volumes:
      - name: keystore-volume
        emptyDir: {}
      - name: spring-music-tls
        secret:
          secretName: spring-music-tls
---
kind: Service
apiVersion: v1
metadata:
  name: spring-music
  namespace: spring-music
spec:
  type: NodePort
  selector:
    app: spring-music
  ports:
  - protocol: TCP
    port: 8443

Keystoreのパスワードは次のようにSecretに保存する。

kubectl -n spring-music create secret generic spring-music \
  --dry-run -o yaml \
  --from-literal server.ssl.key-password=thisisasecret \
  > spring-music-secret.yml

次にTLS証明書を作成する。Let's Encryptなどを使用する場合はここはスキップして良い。

今回はsslip.ioドメインを使用し、この*.sslip.ioに対する自己署名証明書を作成する。

sslip.ioa-b-c-d.sslip.ioa.b.c.dに解決してくれるDNSサービスである。

例えば、10-195-99-214.sslip.io10.195.99.214を返す。

*.sslip.ioに対して、opensslコマンドで自己署名証明書を作成する。こちらからスクリプトをダウンロードし、次のコマンドを実行。

wget https://raw.githubusercontent.com/aws-quickstart/quickstart-pivotal-cloudfoundry/master/scripts/gen_ssl_certs.sh
chmod +x gen_ssl_certs.sh
./gen_ssl_certs.sh sslip.io

この証明書をSecretに保存する。

kubectl -n spring-music create secret tls spring-music-tls \
  --dry-run -o yaml \
  --cert=sslip.io.crt \
  --key=sslip.io.key \
  > spring-music-secret-tls.yml

これでマニフェストが揃ったので、kubectl applyを実行する。

kubectl apply -f spring-music.yml \
  -f spring-music-secret.yml \
  -f spring-music-secret-tls.yml

次のコマンドでログを確認。

kubectl -n spring-music logs \
  -f $(kubectl -n spring-music get pod -l app=spring-music -o jsonpath='{.items[0].metadata.name}')

次のメッセージが出ていればOK

2019-08-19 08:13:27.700  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8443 (https)
$ kubectl -n spring-music get all
NAME                                READY   STATUS    RESTARTS   AGE
pod/spring-music-6d6d57586b-w6mfc   1/1     Running   0          31s

NAME                   TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/spring-music   NodePort   10.100.200.241   <none>        8443:31308/TCP   30s

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/spring-music   1/1     1            1           31s

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/spring-music-6d6d57586b   1         1         1       32s

この例ではtype: NodePortでサービスを公開している。ブラウザでhttps://<Worker NodeのIPの.を-に置換>.sslip.io:<NodePort>にアクセスして動作確認。

image

image


✒️️ Edit  ⏰ History  🗑 Delete