RDSに外出ししたSmart Checkの構成での構築

2020.03.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、ドイツのモナでございます〜

最近はTrendMicro社のDeep Security Smart Checkというコンテナイメージをスキャンするツールをいじりました。簡単にEKSで構築できてとても便利ですね!デフォルトではkubernetesクラスタ内のDBがサービスにより利用されますが、本番環境など、開発環境以外はデータベースを外出しするのがおすすめです。今日はそのデータベースをRDSに外出しする方法を紹介したいと思います。

構成

今回はRDS専用のVPCを作りましたのでその構成で紹介したいと思います。ざっくり、こんな感じです。

準備

overrides.yaml

--- 
db: 
  user: ユーザ
  password: パスワード
  host: xxx.yyy.rds.amazonaws.com
  port: 5432 
  tls:
    ca: 
      valueFrom: 
        configMapKeyRef: 
          name: dssc-db-trust 
            key: ca

dssc-db-trustというconfigmapの作り方は下記です。

構築

RDS

#構築済みのPostgresインスタンス上の手順です

Postgresのインスタンスはデフォルトで"postgres"というDBが作成されますが、それとは別のDBを作成することをおすすめします。

postgres=> CREATE DATABASE xxx;
CREATE DATABASE
postgres=>
#確認
postgres=> SELECT datname FROM database;
       datname       
---------------------
 registryviewsdb
 template0
 rdsadmin
 scandb
 metricsdb
 xxx
 postgres
 template1
 openscapscandb
 vulnerabilityscandb
 authdb
(11 rows)

Postgresは、ユーザ名と同じ名前のDBに接続しようとするので、overrides.yamlのuserを作成したDB名に更新します。デフォルトのDBのままの場合user: postgresを指定します。

あとはRDSのVPCのルートテーブルIDを確認し、エクスポートします。

 $ export RDS_ROUTE_TABLE_ID=rtb-yyy

EKS

今回の構成では、EKSとRDSはそれぞれのVPCで構築されてますが、同じVPCを指定してもOKです。 EKSは色んな設定ができますが、今回は特に何も指定せず最もシンプルな構成で行きたいと思います。

#クラスタ作成
$ eksctl create cluster

overrides.yamlに指定したconfigmapを作ります。.pemファイルがコマンド実行と異なるディレクトリにある場合はパスを適切に指定します。

$ kubectl create configmap dssc-db-trust --from-file=ca=rds-ca-2019-root.pem

Peering Connection

VPC間の接続がうまくいくようにするためにピアリング接続が必要です。

正しい設定:

  • リクエスタ:EKSのVPC
  • アクセプタ:RDSのVPC

なお、作成だけで接続ができるわけではないので、リクエストを承諾することをお忘れなく。

また、RDSにプライベートIPもグローバルIPも両方付いている場合、名前解決がデフォルトでグローバルIPの方になってしまうのでDBとの接続が失敗する可能性があります。そのため、DNSの設定も合わせます。

接続ができたら、VPC間のルーティングも更新します。ピアリング接続のIDを確認後、まずエクスポート。

$ export VPC_PEERING_CONNECTION_ID=pcx-xxx

eksctlは裏でCloudFormationを呼ぶのですが、そこでできたルートテーブルを更新する感じです。

$ aws ec2 describe-route-tables --filters Name="tag:aws:cloudformation:logical-id",Values="PublicRouteTable"
{
    "RouteTables": [
        {
            "Associations": [
                {
                    "Main": true,
                    "RouteTableAssociationId": "rtbassoc-xxx",
                    "RouteTableId": "rtb-xxx"
                }
            ],
            "PropagatingVgws": [],
            "RouteTableId": "rtb-xxx", 
            "Routes": [
                {
                    "DestinationCidrBlock": "10.0.0.0/24",
                    "GatewayId": "local",
                    "Origin": "CreateRouteTable",
                    "State": "active"
                }
            ],
            "Tags": [],
            "VpcId": "vpc-xxx",
            "OwnerId": "xxx"
        }
    ]
}
$ export EKS_ROUTE_TABLE_ID=rtb-xxx
$ aws ec2 create-route --route-table-id ${EKS_ROUTE_TABLE_ID} --destination-cidr-block 10.0.0.0/24 --vpc-peering-connection-id ${VPC_PEERING_CONNECTION_ID}
$ aws ec2 create-route --route-table-id ${RDS_ROUTE_TABLE_ID} --destination-cidr-block 192.168.0.0/16 --vpc-peering-connection-id ${VPC_PEERING_CONNECTION_ID}

DeepSecurity SmartCheck

最後にDeepSecurity SmartCheckをインストールすれば完了です!

$ helm install \
--values overrides.yaml \
--set auth.masterPassword=パスワード \
--set activationCode=取得済みのライセンスコード \
deepsecurity-smartcheck \
https://github.com/deep-security/smartcheck-helm/archive/master.tar.gz
#URL取得
export SERVICE_IP=$(kubectl get svc proxy -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo https://$SERVICE_IP:443/
#初期ログイン情報取得
$ echo Username: $(kubectl get secrets -o jsonpath='{ .data.userName }' deepsecurity-smartcheck-auth | base64 --decode)
$ echo Password: $(kubectl get secrets -o jsonpath='{ .data.password }' deepsecurity-smartcheck-auth | base64 --decode)

取得したURLをブラウザで開いて、初期ログイン情報でSmartCheckのサービスが使えるようになります!

#DeepSecurity SmartCheckについての詳しい説明はこちら

トラブルシューティング

トラブルが起こった場合は、ポッドの状態を確認すればだいたい原因がわかります。

#動作確認
$ kubectl get pods --field-selector='status.phase!=Running'

よくあること:

  • auth-`で始まるポッドがRunningになってない
    • DBとの接続に問題があることが多い
  • image-scan-で始まるポッドだけがRunningになってい
    •  ライセンスに問題があることが多い
NAME                                  READY   STATUS     RESTARTS   AGE
auth-8597859bfc-sgdpb                 0/1     Init:0/1   0          34s
image-scan-5d79cf845f-6qs75           0/5     Init:0/1   0          35s
metrics-5db5fb7788-25tvq              0/1     Init:0/1   0          35s
registryviews-6b9764c785-h7cx6        0/1     Init:0/1   0          35s
scan-7786675c97-9mdsb                 0/1     Init:0/1   0          35s
vulnerability-scan-54f4dc565d-gtqj8   0/1     Init:0/2   0          35s

なお、Runningになってないポッドが一つもなければクラスタとDBの接続には問題がありません!

問題のあるポッドを調べます:

$ kubectl describe pod auth-8597859bfc-sgdpb
#アウトプットが長いので省略
...
Events:
  Type     Reason     Age                From                                                     Message
  ----     ------     ----               ----                                                     -------
  Normal   Scheduled  74s                default-scheduler                                        Successfully assigned default/auth-8597859bfc-sgdpb to ip-192-168-0-155.eu-central-1.compute.internal
  Normal   Pulled     38s (x2 over 74s)  kubelet, ip-192-168-0-155.eu-central-1.compute.internal  Container image "deepsecurity/db-initializer@sha256:97e1f38507fac7a4fde5ce6fe0d9ccb1c51deadd98ed0ef2aabdea1ef3678ec1" already present on machine
  Normal   Created    38s (x2 over 74s)  kubelet, ip-192-168-0-155.eu-central-1.compute.internal  Created container db-init
  Normal   Started    38s (x2 over 74s)  kubelet, ip-192-168-0-155.eu-central-1.compute.internal  Started container db-init
  Warning  BackOff    7s                 kubelet, ip-192-168-0-155.eu-central-1.compute.internal  Back-off restarting failed container
 #詳細ログを確認 
$ kubectl logs -f auth-8597859bfc-sgdpb -c db-init
#アウトプット
{"commit":"79599d853f7704ba61db0d09808f5a1b7d26671e","component":"db-init","message":"Starting up","severity":"audit","timestamp":"2020-03-09T09:48:59Z"}
{"component":"db-init","error":"pq: SSL is not enabled on the server","message":"could not get database connection","severity":"info","timestamp":"2020-03-09T09:48:59Z"}

上記みたいにSSLらしきエラーが出た場合は、まずDBエンジンがPostgreSQLであることをお確認ください!

その他の注意点

  • DeepSecurity SmartCheckのインストール後にoverrides.yamlを更新した場合は、再インストールが必要です
$ helm delete deepsecurity-smartcheck
  • overrides.yaml以外の更新の場合は、ポッドを削除するだけで大丈夫です、自動的に再作成されます
$ kubectl delete pod auth-8597859bfc-sgdpb

最後に

紹介した構成では、EKSクラスタが再構築が必要になったとしても、DBをRDSに外出しすることでデータが無事に残るのがポイントです。また、RDSへ外出しすることでデータのバックアップなども簡単にできるので、さらにメリットがあります!

また、一回基本構成さえ作っておけば、あとは本当に楽ですね!

DeepSecurity SmartCheckを本番環境用に使う時はDBをRDSにしましょう!