controller-runtimeのenvtestでaudit logを有効化する方法
はじめに
こんにちは、サイボウズNecoチームの三村です。
Kubebuilderなどを用いてKubernetesのカスタムコントローラを作成する際、envtestを用いてテストを書くことがあります。
envtestは、Kubernetesのコントローラをテストする際にKubernetesのクラスタを起動することなく、KubernetesのAPIを利用することができるパッケージで、controller-runtimeに含まれています。
この記事では、envtestにおいてkube-apiserverのaudit logを有効化する方法を紹介します。
audit logを有効化することで、全APIリクエストのログを出力できるため、テストのデバッグや分析に役立ちます。
この記事では、Kubebuilderを用いてカスタムコントローラを作成していることを前提としたサンプルコードを掲載しています。テストコードは[1]で紹介されているコードをベースにしています。
audit logの有効化
envtestのsuite_test.go
があるディレクトリに、以下のようなpolicy.yaml
を作成します。
audit logのPolicyの書き方については、こちらを参照してください。
以下のサンプルでは、全てのタイプのリクエストに対して、メタデータレベルのログを出力するようにしています。
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- RequestReceived
omitManagedFields: true
rules:
- level: Metadata
verbs: ["get", "watch", "list", "patch", "update","create", "delete", "deletecollection"]
次に、suite_test.goのBeforeSuite
の中で[2]、以下の様なコードを追加してkube-apiserverのaudit logを有効にするオプションを設定します。
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,
}
var err error
+ workingDir, err := os.Getwd()
+ Expect(err).NotTo(HaveOccurred())
+ apiServer := testEnv.ControlPlane.GetAPIServer()
+ apiServer.Out = GinkgoWriter
+ apiServer.Err = GinkgoWriter
+ apiServer.Configure().
+ Append("audit-policy-file", filepath.Join(workingDir, "policy.yaml")).
+ Append("audit-log-path", "-")
この設定により、audit logが標準出力に出力されるようになります。
このままではテストのログとaudit logがどちらも標準出力に出力されてしまうため、以下の様にgrepするとaudit logのみを出力できます。
make test | grep "audit.k8s.io/v1"
audit logのユーザーを区別する
ここまでで、envtestを実行する際のkube-apiserverのaudit logの有効化ができました。
しかしこのままでは、envtestでテストを実行する際に、コントローラが発行するリクエストと、envtestで記述するテストで発行するリクエストのログが区別できません。
ログを区別可能にするために、Impersonateという仕組みを利用します。
ImpersonateはKubernetesの認証の機能で、リクエストを発行したユーザーを偽装して、別のユーザーになりすますことができます。
このImpersonateの設定をしUserNameをコントローラとenvtestで分けることで、ログを区別することができます。
suite_test.goのBeforeSuite
の中に、さらに以下のコードを追加します。
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,
}
var err error
workingDir, err := os.Getwd()
Expect(err).NotTo(HaveOccurred())
apiServer := testEnv.ControlPlane.GetAPIServer()
apiServer.Out = GinkgoWriter
apiServer.Err = GinkgoWriter
apiServer.Configure().
Append("audit-policy-file", filepath.Join(workingDir, "policy.yaml")).
Append("audit-log-path", "-")
+ cfg.Impersonate = rest.ImpersonationConfig{
+ UserName: "test",
+ Groups: []string{"system:masters", "system:authenticated"},
+ }
// cfg is defined in this file globally.
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
コントローラのテストコードでも同様に、managerに渡すcfgにImpersonateの設定を追加します。
+ cfg.Impersonate = rest.ImpersonationConfig{
+ UserName: "controller",
+ Groups: []string{"system:masters", "system:authenticated"},
+ }
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme,
})
Expect(err).ToNot(HaveOccurred())
この状態でテストを実行すると以下の様なaudit logが出力され、先程設定したimpersonatedUserのフィールドが追加されます。
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "c836b9fc-55b1-4a92-8e19-d7669cf033f6",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/test/services/viewer-sample?fieldManager=markdown-view-controller&force=true",
"verb": "patch",
"user": {
"username": "admin",
"groups": [
"system:masters",
"system:authenticated"
]
},
"impersonatedUser": {
"username": "test",
"groups": [
"system:masters",
"system:authenticated"
]
},
"sourceIPs": [
"127.0.0.1"
],
...
このようにImpersonateを設定することで、envtestでテストを実行する際に、コントローラが発行するリクエストはImpersonate.UserName:controller
、envtestで記述するテストで発行するリクエストはImpersonate.UserName:test
がログに記録されるようになりました。これにより、envtestでテストを実行する際にログを区別できるようになります。
まとめ
envtestでテストを書く際に、kube-apiserverのaudit logを有効化する方法を紹介しました。
また、コントローラとテストで発行するリクエストのログを区別する方法も紹介しました。
audit logを分析することにより、envtestに問題があった際の原因特定がしやすくなります。
-
コントローラーのテスト - つくって学ぶKubebuilder https://zoetrope.github.io/kubebuilder-training/controller-runtime/controller_test.html ↩︎
-
テストスイートにGinkgoを使用している想定で記載しています。controller-genが生成するenvtestではGinkgoが使用されています。 ↩︎
Discussion