背景
Kubernetes環境でGitOpsを導入するにあたり、Secretの扱いをどうするか、という課題に直面しました。
GitOpsでは、KubernetesのマニフェストファイルはGitで管理するので、工夫しないとSecretをそのままコミットすることになってしまいます。
Secretの値はbase64でエンコードされているだけなので、簡単にデコードできてしまうため、そのままコミットすることは好ましくありません。
そこで対応方法を調査した結果、SealedSecretというものを見つけ検証したので、本番環境でも有用な使い方をまとめることにしました。
準備
kubesealのインストール
まず最初に、kubeseal
をインストールする必要があります。
手順は以下のリンクに載っているので、ぜひご覧ください。
sealed-secrets - releases
ここでは、Macでの手順をご紹介します。
$ # kubesealのインストール
$ brew install kubeseal
$ # バージョンの確認
$ kubeseal --version
kubeseal version: v0.12.5
SealedSecret関連のオブジェクトを生成
SealedSecretのCustomResourceDefinitions(CRD)をインストールします。
$ # sealed-secrets-controllerに関連するオブジェクトを生成
$ kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.12.5/controller.yaml
kubesealのヘルプを見ると、namespaceのデフォルトはkube-system
のようです。
$ kubeseal -h
...
--controller-name string Name of sealed-secrets controller. (default "sealed-secrets-controller")
--controller-namespace string Namespace of sealed-secrets controller. (default "kube-system")
...
必要なオブジェクトが生成されているか確認します。
$ # Podの確認
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
...
sealed-secrets-controller-867447b788-7sdhq 1/1 Running 0 8m58s
...
$ # Secretの確認
$ kubectl get secrets -n kube-system
NAME TYPE DATA AGE
...
sealed-secrets-controller-token-xplmz kubernetes.io/service-account-token 3 23h
sealed-secrets-key4wlwz kubernetes.io/tls 2 9m56s
...
無事に生成されていることが確認できると思います。
これで準備は完了です。
Secretを暗号化する(SealedSecretを生成する)
ここからは使い方を紹介していきます。
証明書の取得
Secretを暗号化するために必要な証明書を取得します。
証明書はコミットする必要がないので、.gitignore
に追加するなどしてコミットできないようにすることをお勧めします。
$ kubeseal --fetch-cert > cert.pem
暗号化するSecretのyamlを生成
すでにSecretが作成されている場合は、それを元にyamlを生成しても構いません。
このyamlもコミットする必要がないので、.gitignore
に追加するなどしてコミットできないようにすることをお勧めします。
$ # sample-secretという名前のSecretのyamlを生成
$ kubectl -n default create secret generic sample-secret \
--from-literal=MYSQL_HOST=localhost \
--from-literal=MYSQL_USER=root \
--from-literal=MYSQL_PASSWORD=password \
--dry-run=client \
-o yaml > secret.yaml
生成されたSecretのyamlはこちら。
apiVersion: v1
data:
MYSQL_HOST: bG9jYWxob3N0
MYSQL_PASSWORD: cGFzc3dvcmQ=
MYSQL_USER: cm9vdA==
kind: Secret
metadata:
creationTimestamp: null
name: sample-secret
namespace: default
SealedSecretのyamlを生成
上記で生成されたSecretのyamlを用いて、SealedSecretのyamlを生成します。
このとき、証明書の指定
やフォーマットの指定
を忘れないでください。
$ kubeseal --format=yaml --cert=cert.pem \
< secret.yaml \
> sealed-secret.yaml
生成されたSealedSecretのyamlはこちら。
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
creationTimestamp: null
name: sample-secret
namespace: default
spec:
encryptedData:
MYSQL_HOST: AgBPhntyTvUOYPtjJrdZk0fbVyljZFQExAVKAHYjE0rtTNsqaNXygninGs5CPPALfIf/BgmONK35xepHnH7kqc+WNm2nt4MueAMHAtrHQ/8SCkzXbQGLuiyUUds2Q2xVu/rBAVwGfWaKkwi9Db8Y7u6UOLE2wjgk2hpfqnf0KCgR4+u4q936tszBlqQrzk6+ZCqn7oPkOHI3iHJIi4Myo+Xh51Cx0ItEcq18huAK04tTgPoNDJgjLZZnWt83eOJcdqs6mNuI2khsi+/sXizA/naRRDJjiZat5//v/e73ejPRYLJkLCxmbiqBkZUmzBcTgj9PNvOPd+Be/VlKV0I4oO23e4f4CTp+xsq/hxje1qo38zL5UEalbYvtWVCAQCHyA5zcacpD7Sbl0hDSn4JCmXgktrtmgp4iADw2dGDqj7yGyvgQt18VUyWwqIzdhdih9a9LLvqK+gEf9pHs6p6j+rSlvIhKWM9k+vp44h9GLv5ViXB0jFD6Ig5kuyrne6OPceJgj1kuoGQbGdwCvd6thjNytWwBuPujKo5AK4VepLUUh7q7zZwqBv0yXMwSkmFDpJMTmMuy6W32HZvmJw1m/ajaAqlltDKl2pbyDClRLJ/K1n9QDiOEgIdLX3t9C5tJL1G9b1bMTpTfqqYcQbTQnDBEJJ7du4eYQRoT9EP4vI0eyab8beuvBvwIdPvsPWwY+uf7TzuyX0ve6/8=
MYSQL_PASSWORD: AgAV4O7rOmyqL2JtPZ/XtUIMNW5GPgSMhc8zU0zU7LyaNfu5PPFfZrqmyvV4u0XjiNL0nH0rxCEnbm8ZlYtDQCDTMAZMgQkDSWVq7RGnL0txkE3mtsgzctNvIk54lvoVi7fzsBUHXLWsXu58NgQsGhc/VG25zMIq2ycEKd0nEFoa3EK1EoNsb3gKNS4qGM7hqkS5y7ufOcUR5mVuvXlihrfn9nGcucFsRsMbxsTYWUauM8x0wqxrnw7o74EkA0Gyhu2FI43n4mleubC8pzOEYvurfyfd1UmS7H6j/Cm4VuPtiX/uynvKyb2iVJX3vkeyKnmvhP6AcegfI1UYSD1nLg6taDOUFDdScCRsdI97lF0ehYauinLLp94rRQIXOFWYaSqq8VNbQzApXTDAgSzjazdx17p1IVrspEc7xCzD1Dcn3RiiiSpGnYEbG4rF4pFu8AcKH5j/MSydKN4iJgQ2utOgJ7pUXNeShgRrNf/BI67uus44fgeIXnkG8+LG7/WGhsjnYTRsECZD4g+q2vB3tYeBSFQ7ojUFVN5ChsZgTS+uziIp3jzxu3sWfSt4puGx+BlFp+dxv0Zp1YrRKuje+dBWlCkrf9Sa16SR7DCqKdX+1G0W6rwYYEyXwRW9Y0s6lUZwfpd0kOVcYZABohfH3RkWmxgKjF76xFlyFfHILVtdGJbe1nz1144wAMQeE3jvk/ypeAGy+I8lbg==
MYSQL_USER: AgDjq7qBJR1DDOWapYF4AhtQi1sQgeglSRhu6tZ+JHPTPPdNFBV+zQk3xzKKRldZeeIlXQ5ZquEdc3lMWYKqg5xvL2e21YhgPv4oWADDvsWxWdklZVLDl0SGPQT64v6K+lPVR5Gia6zIpocvv4v3GbMcCXFkFK/b5HeSU6FcxrAhrQ+vdxSWKfkezO8vrS1wJ3MYLgLSwtiRDsibjpYwVTg0sLDcpTlrDk95IEnmcY8bE6qGJ3BO8mUBPhsBnk5yLJO2MZeOofA9IbpUDIpUJSFcaaXc+PK3C+vKxxJ2Ia94Y07UshUOrl72dTrp9aJv1mdkVfzZ7EHQpHh+2k7b2U1nMFVFwK2QV193vJVSQDM21IzIttE4QOxllv0ei48FVMVw3pJ0ABJMKiYta6KAZvKQ5EJkEIVVHtVqRH6plpBgU72dAPVuJAmdlAQ3I844lj1AKwfydylFRJP/olkHegB5Lu3ScwblicPZt4Q+f+IV79YefKR+Bf8zwLB5bd5uFOVx5Jj3dkiSfTN9P60FE6uA1axxyECafqwcgEmxafODtRpP+94rbAUboWCCXTAqjL+KyclCkXg0lKKLDHBmIzhsV3+eDwlApHWfvs1/x2dyW17Rjs7Nqb6vi/xX+YXT0d67TzNEUFfYFABRN9ABN/YSCWsVxIJXvMulg4RpsGD4g5E4GG5gwj3Jjjfr0yEtsu9fS5Zn
template:
metadata:
creationTimestamp: null
name: sample-secret
namespace: default
ご覧の通り、暗号化されるのは、ファイル全体ではなくSecretの各キーに対する値
です。
これをapplyすると、Secretが生成されます。そのSecretを確認すると、前述のSecretと一致するはずです。
Gitにはこのファイルをコミットします。
基本的な手順はこれで終わりです。
鍵の扱い
バックアップ
Kubernetesクラスターにある秘密鍵と証明書は、Secretになっています。
これを削除してしまったり、クラスターそのものを削除してしまった場合に、SealedSecretを復号できなくなってしまいます。
それを防ぐ為に、このSecretは必ずバックアップを取りましょう。
$ # ラベルを指定して、Secretを取得
$ kubectl get secret -n kube-system \
-l sealedsecrets.bitnami.com/sealed-secrets-key=active \
-o yaml > sealed-secrets-key.yaml
生成されたSecretのyamlはこちら。
apiVersion: v1
items:
- apiVersion: v1
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVyakNDQXBhZ0F3SUJBZ0lSQUpsYnRkeUI5bmRqZ1ljZFI1Qkh0dk13RFFZSktvWklodmNOQVFFTEJRQXcKQURBZUZ3MHlNREE1TWpReE5ESXhNRGxhRncwek1EQTVNakl4TkRJeE1EbGFNQUF3Z2dJaU1BMEdDU3FHU0liMwpEUUVCQVFVQUE0SUNEd0F3Z2dJS0FvSUNBUUR5cVJQT3pCSzk4UFZvVlJBYVJJV1gyS3dSdmJIZVBMTnhxY2Q4CmQ3UlM2a3pDZUhINzFFa0E2NzlyQWoxZVUzQ3g0dG8zTlNPWkhqNEFIVk1OS256WTVWYXRFY1F4WEZOWjdRci8Kb2hKTFNuS1VHVG55UCszZU55S29wY3hYeUlibkdlUmh0elVQOTRPdzAyWld5MHEreDdyS29uZk11ZUNMTlNsRwpqeXVKelN3UW9HZUFCbXZYL2NUc29pTHNRdHJoK1Jvc29ZL3VIYU1KNDlYaytiSzRrWFJBeEZPenh3dUZGd0JZCk9NVEZnS3d3WWlaM1l2RytOYjBwWGx6MyttZ1NTVkxRem9CallPT0tMRloxWnBBMXRKYWJIcVhwdUF6b2FJOFUKL0svQjV1cWxLNngrMnhtYUFvcjUxTHZubEdxWER4K2hOZXRDd0NUMVB4Uk5PS0ErNTRiTmVaUjh5alVGMDM5MQpUOXM4a1ZKT2RjN3VTTVdkbytCSUVGM2tJcjdiNThrcThiRTdVcERUOUVybG8va2xhNmZOV2hSaldGR3VHdjgrClJCaUZYZFVxZHZTeVNOTC91VndUVHN2SWpZQ2RqajJsMDZJM2lvQWxsUjQvejNDa21ORW5hQ1oxVmEyclRMc0IKRW5yRHhmRGJsUnhMVHpENWRZVHJ1MTd0MTdadHc3emp1Q3RRWlViM2NzWlJER1EwTzlYcWxZbjZJQzVaRjRxeQpXOFF1b3N6Wlo1cVAwSVFXOUZsK3Nvb3lCbjJhdmNtNnZoMFBvOVZYNGl1U2NLcnBKUkFaNHlIYnRIQlJxTXZOCklFYXBua2dZVk1XMGF0UkN1c2gzTktIaFNCakYyM1ZXMWV4Y01lbFdFWVc4TWhub0d2S1RnZjI5ZW9oMjllVXYKdlZNeVhRSURBUUFCb3lNd0lUQU9CZ05WSFE4QkFmOEVCQU1DQUFFd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBTgpCZ2txaGtpRzl3MEJBUXNGQUFPQ0FnRUFaWkRrblBvWVRrTXltTU01cHdlZ2JLSmRwQlRDRDgvbUR3dUZBS1ZRCkhia0lCMVR1NmVwOVgzbzYxQVF4ZWF3Ukd5NVRvS29pVHNqUTRhcCsrNUJqYmpWZHdBREpZWVd6d2twR0taenAKTDFXV3IyTlQzOXYvR1dPOHl3ZnlUb3BQcjZPN3h5dVRPYk4vb0JjdC9lVVZVV3gzemZyM1hxb3FLZ3IzTDlTLwpuYU5abEc1ZFcvNTNEcEFTSHNEMVgrRWZOQXQ5KzZtMXZpZm5FRmxFQmVWeU02Mm9NQ3NPbFdNVGNEcnBIN0JrCkthSTM4Zno2aTQzd3pJK1ZncDAzVUx0aVVsMnZ4ZVdJbHdFcXVGeUZoTDFkeFBqR0JFNHAraGhCNGR3a3hGVEgKelk1bVFweUhJNWdvK1FvQk1pclZzcFZXeW9HNHo3WUJNdGZSamYweWdWUXlXd2RPbUpZMDF3NVM4ektMMG9tYgpmZU5wbWdFY1NkNWo3SEIydklnVWJGVWxlaERIZkszcXFGR2FsOXYwMXZWckJ5aklnRW9TUGhUOVFlVkh6TXk1CnI4Ump1TkZiUWZidXVWazRCd1hHeW9tYUJUdkdqVXhqMWRHRlRPNjdTMHMvMFBzOVpGM29ONkdZbFRQZDQ2WjYKeHJ5b2FqMXA2V2s3VVhBaGlWd3E3VFhMZEhPcVIxZnl5RFF3eEJLYTArTkI0NHlqcXp6Tmk5TzRuYnovM2hLagpHK1JpcWdFaFFkTUg5MVFkcGVvUUZKeUFmQzVQcnBxUkVoQUY3dG5mUExqOTZRTlJGS0pXeW5MRXFma3cxN0tGCnlvbWFUMmVVZ05Ock11emczdXB4UXNsakp6d2RQLzZxYklmb1Uwa0V1TXo3V3gvQ09WeGtqWDdlckZNT0N2cUIKcWQ0PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBOHFrVHpzd1N2ZkQxYUZVUUdrU0ZsOWlzRWIyeDNqeXpjYW5IZkhlMFV1cE13bmh4Cis5UkpBT3UvYXdJOVhsTndzZUxhTnpVam1SNCtBQjFURFNwODJPVldyUkhFTVZ4VFdlMEsvNklTUzBweWxCazUKOGovdDNqY2lxS1hNVjhpRzV4bmtZYmMxRC9lRHNOTm1Wc3RLdnNlNnlxSjN6TG5naXpVcFJvOHJpYzBzRUtCbgpnQVpyMS8zRTdLSWk3RUxhNGZrYUxLR1A3aDJqQ2VQVjVQbXl1SkYwUU1SVHM4Y0xoUmNBV0RqRXhZQ3NNR0ltCmQyTHh2alc5S1Y1YzkvcG9Fa2xTME02QVkyRGppaXhXZFdhUU5iU1dteDZsNmJnTTZHaVBGUHl2d2VicXBTdXMKZnRzWm1nS0srZFM3NTVScWx3OGZvVFhyUXNBazlUOFVUVGlnUHVlR3pYbVVmTW8xQmROL2RVL2JQSkZTVG5YTwo3a2pGbmFQZ1NCQmQ1Q0srMitmSkt2R3hPMUtRMC9SSzVhUDVKV3VuelZvVVkxaFJyaHIvUGtRWWhWM1ZLbmIwCnNralMvN2xjRTA3THlJMkFuWTQ5cGRPaU40cUFKWlVlUDg5d3BKalJKMmdtZFZXdHEweTdBUko2dzhYdzI1VWMKUzA4dytYV0U2N3RlN2RlMmJjTzg0N2dyVUdWRzkzTEdVUXhrTkR2VjZwV0oraUF1V1JlS3NsdkVMcUxNMldlYQpqOUNFRnZSWmZyS0tNZ1o5bXIzSnVyNGRENlBWVitJcmtuQ3E2U1VRR2VNaDI3UndVYWpMelNCR3FaNUlHRlRGCnRHclVRcnJJZHpTaDRVZ1l4ZHQxVnRYc1hESHBWaEdGdkRJWjZCcnlrNEg5dlhxSWR2WGxMNzFUTWwwQ0F3RUEKQVFLQ0FnQnNOcTVZcUhVck0wdWRiV0d5OVIvR2FaL0NnWi9TaGF0WVl1aE5QMnl4RlQrSjhnQ1MxMFovSEtMTwphNzlHVTF1TVdLZ0x1cXpYV2I4NGVkdFJvY0x2VHNicWcyUEV4M0Y4UnRPQzBKbnI3WlZQS2pqSEtXOUFpOEh2CkI1RXJESWZzZzRWdmRpNDVvcDJkdTRpRjZENjYrWUw1WHA2aU03cEpHam4vOTFUcExSQWJrZ3pWOFFjaTJVNTYKWUl2R1pNSUx4L1MrTm9aakgrQlhScjFhVVdnOEd0R0hHSVpqUTc2RmFZNkR5VDBtL296TFB0bjhuNmxDcytCWgpsSFZOT09RMFUzS1ZINkh0cjRXSlZ1QnZsbjkxRThXZUEzcmwwV2dnTkpDcVFVMTM0U3grNEEwYXZVYWJnY3JNClF1eFJCOFRJL0x1VVB1RmRjU2FLSDhsRDdwNjIwR1dzcDBXditMMWJlY3N6YkphcHRhMzhsUnNrLy8rUmpCMW8KUWszRXRkNnZWblZxVTF1Q0FDdlYzcWplY25Kd244QkJ1OElyOXdXMHFSR1RQUUhKak5pMzdYVC95RVJGNjJtVApHMEVodmVjQnZqdE5QcVE5OUdGc2l0YUtFeGhSK3FWTWZDZktVQ2dMZmRGYTFvU0x3NFVJY2NrZzZ1Ymxoc2YyCmxIaHBDWlpzL3piQzFxbDJob3NHRHR2YnNzOEIwbTJWdW9HalFuMHF2SEFZeEMrZG9QK3FZTlB6VjRxS1VweFUKV0RXZEZ5QXRvZ0M4bVgyMXZvbHNvU3grRWdrVW5ZV0Z6WmViQXpleTFuZGxXNnVQcmJBQUM0aVQ0VUFRZko1aAo3Q0hIUlo4M2V4ZGo4L1Fnd0FBZHByZXplV3VTNFdyUVJYOVl1WGJudXE3OEFLWEFtUUtDQVFFQSs3a3l1Z3lVCmxRYXlsNFV4Qmp5ajdSTCtTWGErbXYwWkhUQVd5dXhra2FsSHNCYms1U0hNT2RBbWFrR1hJdEhTckxZMEd3Yi8KRys2WC9YQWYybFZtZUlBRUM3WlJiRk9kRHE1TXBZZkdSWmpBZWNRamRJQjQvMWNMNnExT2dRMjZtaFNaalJKegpFQnVocVQwNHJIcmovQ2lyT2lER3dMUDJlejg2aXViOHB6YWtkeEMwMERsLzliTDNPWWJmWG1wL29BcDZYem9pCnExcUpzdzIzTFJSNlNkd29xQmlZdHczZ1hJK3dPV3ozci9uNUFJOHNuSUVwdGNrTjVLYWQ0NnlYOEpzSFYvVjcKNnBqeWU3cWpkRVp3TktGRGlDeWhVVFA0bit1WW5TblhjeTdteTUwNkh0V2M4SHNNekRyclFFeFZsSkY3UitPMQo3ZmhnbG55V0tBcGVDd0tDQVFFQTlzaDJXb2hyOWpVUlk1M0s2NVFpa0JxQkUySCs2aGhSc0pXaGhBbUlwUUlmCmFTVVorNThIL0JmMGx5czdCNTUxU24xVTlWNmxQTFNOQm5lb25OWnIzZ0hwaGNhN2o5Rm45Y2tpdHVTZzhDN3MKSGg1RzEvOVptSDlvRTdPRjRwSzdCT1JVUGVHRUdsbE1QdWpNYVV4a3BpamJhdmFXd2htU2NNN1E4bVFxKzhYUwpIVkpoMW5uUmpwY1B0ZzBwSVFnZUtkTFViMytRZ1RXV3B6RWg1V2NKNjY2OCtNWDBJRENoWUdOOVFINklWNDNmCm9ZZE1reE1WajVoQXQ3dVZ4UzdrQmY4a2o0RndmbmhIc3hta3NpMUp0aTBMUUZJWUhLaEh3RjhRTjYzM1RWNFUKbENNcm9Sb3NzWVpwbGRUR0c3TE5IYm05NFd6MStJUVlIRkxNL0crNk53S0NBUUJIY1FCY25VVnVKa0I1a0d1aApnWVJrdkljL0FseUdVRjdZVWRXbU1nRTQ5ZnBLbDdUTzh4Q3JOOUF2Ui81RSs1ZjNQSjc5TExjcWprVEV3UlhKCk9ZT2puM0dHZ1hBS2RwQ1VvaE5PeDRJV0xvd3lBdUN0SitrdlR0MHE5WlRhTzdOQ0Y2YWN5eWVzNHFxM0JaRVkKSXFpaDRFajRibVQ2UEJrd1VYbWtBbnFpV25mQzh4TGVKZk9USC8vYWE5VHBUd0I1dzMrSGwxQlBvWnFESHRsbQpDZkhMRkpqVlhHVzdUa3ptK0VEamkzR2dtQ2w3WnljYUkrNWFrWDFINzZIUUJDUDdQWVNRQ2pQcEdROTQzamVWCndJZ0g1OXpxd1AvbnRBQlVJdUZsZVlLVVJqTnFobTBBWTAvdlVIMEpXWTk2NkM5Qnd5aGg5dGFqZTJLdVV4MnEKcjRhUkFvSUJBRTQvaWFkekVpaGk4enlPejhTYWw4cnhYSFAwNG9yL1l3ZUdxa3ZmYWdCSUNBV2l5ZlpLbXBHSQpWdm1IcjVQZTNubmIrNUJCamtzTlJKb0VYdVk3NXIvaUExVnppZzB6N0s2Mk05ZWg3cFc1aXd5UnRRelAzbXpJCkdRd0dKREdQTE5XRVFHSE9tOEJ2Q0FuNmJyWUVqdlZRaHlJSFJnNE5aYTEzSmpGMUtWdmpnWmZpZ3pzcUxSUDEKT2ZvVGVqTUxDK1ZmQUJUS2NkdEdUcHA4cmE2N1dSM3RyZVdEZnNDbUtzVVJScW1vZFRxdHRYYldHNldXcTRONApWeXpxd2JaZ0E5VVM3VmpEUmhRVHQwaEduVDRSdGdtWmhyUENVL3JpTUw0Q1puWUJKeVRVNjlsOHZWeTdtK2crCklrUnJ6dFVCZ0tBb1FOaTFYOWlJcWN4eFJLWFdGMGtDZ2dFQkFNQXVjWEs4eGo5VEJuWkdGMW5mR2pOWlFQWkcKb2UvMEdOaWpHVUtUZkN1dXZNcU16Tm1JeVY2VlVFNXhiaWVFNElIbE5EQXROSG5uYTBnNWUxb0cycDdISWo2cApWNG10QVlMYUU0dTg4c3hFMFdKNHVEUVN3aWg3b0Q5UWkrTUN1R1ZZRTY3LzNDbElZdFhaK2dpSWRRY3ZEcDNwCk9WVzlXYjhENk1mSTQ0Ukp4RlFQb2hheU9LazAvOXVuck1vQlAzZXdpcVRLY2EwNFZ2V2dONHVaU3pMQ0wwaDQKeUJiL3AwdUNlcW1XOUhLSWlsdXc0NmN3OVdOZnZPVDZYZHB4b25LNysya2RieTQ4VFk0QVpNa3JEU21JYzkwTApXeFFlb2NlYWkxUlRIRG9Ock44dzB5Qk1WOGNKYjdsRW9yY21xV0tteEZ6cjNoQjRyRktrc3hlZE93ST0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K
kind: Secret
metadata:
creationTimestamp: "2020-09-24T14:21:09Z"
generateName: sealed-secrets-key
labels:
sealedsecrets.bitnami.com/sealed-secrets-key: active
name: sealed-secrets-key4wlwz
namespace: kube-system
resourceVersion: "3522389"
selfLink: /api/v1/namespaces/kube-system/secrets/sealed-secrets-key4wlwz
uid: 1fb9a39d-1b5f-4a4b-a47f-ebd56d02303d
type: kubernetes.io/tls
kind: List
metadata:
resourceVersion: ""
selfLink: ""
local環境用の鍵はそのままコミットしても構わないと思いますが、ステージングや本番などの鍵はそうはいきません。
何もせずにコミットしてしまうと、SealedSecretからSecretを生成できてしますので、SealedSecretを使う意味がなくなってしまいます。
KMSなどを使用して暗号化してからコミットしましょう。
バックアップから証明書を取得
上記のsealed-secrets-key.yaml
から証明書を取得します。
ここでは、yqコマンドを使用します。
$ yq r sealed-secrets-key.yaml 'items.*.data."tls.crt"' | base64 --decode > cert.pem
鍵のリストア
バックアップした鍵をクラスターにリストアします。
ここでは、鍵のSecretがない場合の手順を紹介しますが、残っている場合は事前に削除してください。
$ # 鍵のSecretを生成
$ kubectl apply -f sealed-secrets-key.yaml
$ # Secretを生成しただけでは反映されないので、ControllerのPodを再生成する
$ # このPodはDeploymentによって生成されているので、Podを削除するとすぐに生成される
$ kubectl delete pods -n kube-system -l name=sealed-secrets-controller
$ # ControllerのPodが作り直されたことを確認
$ kubectl get pods -n kube-system -l name=sealed-secrets-controller
NAME READY STATUS RESTARTS AGE
sealed-secrets-controller-867447b788-zhrg4 1/1 Running 0 18s
Secretの内容を更新する
運用していると、Secretを更新したい場面があると思います。
しかし、SecretはSealedSecretとして暗号化されているので、簡単には更新できません。
そこで、SealedSecretを復号してから更新する手順を紹介します。
もちろんクラスターからSecretを取得しても構いません。
$ # バックアップした鍵のyamlを渡して、SealedSecretを復号する
$ kubeseal \
--controller-namespace=kube-system \
--controller-name=sealed-secrets-controller \
< sealed-secret.yaml \
--recovery-unseal \
--recovery-private-key sealed-secrets-key.yaml -o yaml > secret.yaml
$ echo -n 'user' | base64
dXNlcg==
Secretの値を上記の値で更新し、再度SealedSecretのyamlを生成すれば完了です。
環境毎にSealedSecretを管理する
Kustomizeを使用することで、環境毎にSealedSecretを管理できます。
Kustomizeの使い方に関しては、公式のドキュメント等をご覧ください。
前提として、以下のディレクトリが作成されているとします。
パス | 説明 |
---|---|
base/ | 全環境共通のyamlを置く。 |
overlays/local/ | local環境用のyamlを置く。name やnamespace が一致するオブジェクトの値を上書くことができる。 |
base/
には、name
とnamespace
を定義したyamlを置きます。
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: sample-secret
namespace: default
overlays/local/
には、local環境用の具体的な値を持つSealedSecretのyamlを置きます。
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
creationTimestamp: null
name: sample-secret
namespace: default
spec:
encryptedData:
MYSQL_HOST: AgBPhntyTvUOYPtjJrdZk0fbVyljZFQExAVKAHYjE0rtTNsqaNXygninGs5CPPALfIf/BgmONK35xepHnH7kqc+WNm2nt4MueAMHAtrHQ/8SCkzXbQGLuiyUUds2Q2xVu/rBAVwGfWaKkwi9Db8Y7u6UOLE2wjgk2hpfqnf0KCgR4+u4q936tszBlqQrzk6+ZCqn7oPkOHI3iHJIi4Myo+Xh51Cx0ItEcq18huAK04tTgPoNDJgjLZZnWt83eOJcdqs6mNuI2khsi+/sXizA/naRRDJjiZat5//v/e73ejPRYLJkLCxmbiqBkZUmzBcTgj9PNvOPd+Be/VlKV0I4oO23e4f4CTp+xsq/hxje1qo38zL5UEalbYvtWVCAQCHyA5zcacpD7Sbl0hDSn4JCmXgktrtmgp4iADw2dGDqj7yGyvgQt18VUyWwqIzdhdih9a9LLvqK+gEf9pHs6p6j+rSlvIhKWM9k+vp44h9GLv5ViXB0jFD6Ig5kuyrne6OPceJgj1kuoGQbGdwCvd6thjNytWwBuPujKo5AK4VepLUUh7q7zZwqBv0yXMwSkmFDpJMTmMuy6W32HZvmJw1m/ajaAqlltDKl2pbyDClRLJ/K1n9QDiOEgIdLX3t9C5tJL1G9b1bMTpTfqqYcQbTQnDBEJJ7du4eYQRoT9EP4vI0eyab8beuvBvwIdPvsPWwY+uf7TzuyX0ve6/8=
MYSQL_PASSWORD: AgAV4O7rOmyqL2JtPZ/XtUIMNW5GPgSMhc8zU0zU7LyaNfu5PPFfZrqmyvV4u0XjiNL0nH0rxCEnbm8ZlYtDQCDTMAZMgQkDSWVq7RGnL0txkE3mtsgzctNvIk54lvoVi7fzsBUHXLWsXu58NgQsGhc/VG25zMIq2ycEKd0nEFoa3EK1EoNsb3gKNS4qGM7hqkS5y7ufOcUR5mVuvXlihrfn9nGcucFsRsMbxsTYWUauM8x0wqxrnw7o74EkA0Gyhu2FI43n4mleubC8pzOEYvurfyfd1UmS7H6j/Cm4VuPtiX/uynvKyb2iVJX3vkeyKnmvhP6AcegfI1UYSD1nLg6taDOUFDdScCRsdI97lF0ehYauinLLp94rRQIXOFWYaSqq8VNbQzApXTDAgSzjazdx17p1IVrspEc7xCzD1Dcn3RiiiSpGnYEbG4rF4pFu8AcKH5j/MSydKN4iJgQ2utOgJ7pUXNeShgRrNf/BI67uus44fgeIXnkG8+LG7/WGhsjnYTRsECZD4g+q2vB3tYeBSFQ7ojUFVN5ChsZgTS+uziIp3jzxu3sWfSt4puGx+BlFp+dxv0Zp1YrRKuje+dBWlCkrf9Sa16SR7DCqKdX+1G0W6rwYYEyXwRW9Y0s6lUZwfpd0kOVcYZABohfH3RkWmxgKjF76xFlyFfHILVtdGJbe1nz1144wAMQeE3jvk/ypeAGy+I8lbg==
MYSQL_USER: AgDjq7qBJR1DDOWapYF4AhtQi1sQgeglSRhu6tZ+JHPTPPdNFBV+zQk3xzKKRldZeeIlXQ5ZquEdc3lMWYKqg5xvL2e21YhgPv4oWADDvsWxWdklZVLDl0SGPQT64v6K+lPVR5Gia6zIpocvv4v3GbMcCXFkFK/b5HeSU6FcxrAhrQ+vdxSWKfkezO8vrS1wJ3MYLgLSwtiRDsibjpYwVTg0sLDcpTlrDk95IEnmcY8bE6qGJ3BO8mUBPhsBnk5yLJO2MZeOofA9IbpUDIpUJSFcaaXc+PK3C+vKxxJ2Ia94Y07UshUOrl72dTrp9aJv1mdkVfzZ7EHQpHh+2k7b2U1nMFVFwK2QV193vJVSQDM21IzIttE4QOxllv0ei48FVMVw3pJ0ABJMKiYta6KAZvKQ5EJkEIVVHtVqRH6plpBgU72dAPVuJAmdlAQ3I844lj1AKwfydylFRJP/olkHegB5Lu3ScwblicPZt4Q+f+IV79YefKR+Bf8zwLB5bd5uFOVx5Jj3dkiSfTN9P60FE6uA1axxyECafqwcgEmxafODtRpP+94rbAUboWCCXTAqjL+KyclCkXg0lKKLDHBmIzhsV3+eDwlApHWfvs1/x2dyW17Rjs7Nqb6vi/xX+YXT0d67TzNEUFfYFABRN9ABN/YSCWsVxIJXvMulg4RpsGD4g5E4GG5gwj3Jjjfr0yEtsu9fS5Zn
template:
metadata:
creationTimestamp: null
name: sample-secret
namespace: default
このように配置し、kustomization.yaml
を作成した上で、kustomize build overlays/local/ | kubectl apply -f -
を実行すると、local環境用にSealedSecretが上書かれてSecretが生成されるようになります。
stagingやproductionなどの環境に対しても同様の方法で、環境毎のSealedSecretを定義できます。
まとめ
SecretをGit管理できるようになったので、安心してGitOpsを導入できるようになりました。
Secretの扱いに関しては他にもツールがあるので、各プロジェクトに応じて選択していただければと思います。