123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /*
- Copyright 2019 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package gci
- import (
- "fmt"
- "io/ioutil"
- "path/filepath"
- "testing"
- "k8s.io/apiserver/pkg/apis/audit"
- auditinstall "k8s.io/apiserver/pkg/apis/audit/install"
- auditpkg "k8s.io/apiserver/pkg/audit"
- auditpolicy "k8s.io/apiserver/pkg/audit/policy"
- "k8s.io/apiserver/pkg/authentication/user"
- "k8s.io/apiserver/pkg/authorization/authorizer"
- "k8s.io/kubernetes/pkg/serviceaccount"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- func init() {
- // Register audit scheme to parse audit config.
- auditinstall.Install(auditpkg.Scheme)
- }
- func TestCreateMasterAuditPolicy(t *testing.T) {
- baseDir, err := ioutil.TempDir("", "configure-helper-test") // cleaned up by c.tearDown()
- require.NoError(t, err, "Failed to create temp directory")
- policyFile := filepath.Join(baseDir, "audit_policy.yaml")
- c := ManifestTestCase{
- t: t,
- kubeHome: baseDir,
- manifestFuncName: fmt.Sprintf("create-master-audit-policy %s", policyFile),
- }
- defer c.tearDown()
- // Initialize required environment variables.
- c.mustInvokeFunc(
- kubeAPIServerEnv{KubeHome: c.kubeHome},
- "configure-helper.sh",
- "base.template",
- "testdata/kube-apiserver/base.template",
- )
- policy, err := auditpolicy.LoadPolicyFromFile(policyFile)
- require.NoError(t, err, "Failed to load generated policy.")
- // Users for test cases
- var (
- anonymous = newUserInfo(user.Anonymous, user.AllUnauthenticated)
- kubeproxy = newUserInfo(user.KubeProxy, user.AllAuthenticated)
- ingress = newUserInfo("system:unsecured", user.AllAuthenticated, user.SystemPrivilegedGroup)
- kubelet = newUserInfo("kubelet", user.AllAuthenticated, user.NodesGroup)
- node = newUserInfo("system:node:node-123", user.AllAuthenticated, user.NodesGroup)
- controller = newUserInfo(user.KubeControllerManager, user.AllAuthenticated)
- scheduler = newUserInfo(user.KubeScheduler, user.AllAuthenticated)
- apiserver = newUserInfo(user.APIServerUser, user.SystemPrivilegedGroup)
- autoscaler = newUserInfo("cluster-autoscaler", user.AllAuthenticated)
- npd = newUserInfo("system:node-problem-detector", user.AllAuthenticated)
- npdSA = serviceaccount.UserInfo("kube-system", "node-problem-detector", "")
- namespaceController = serviceaccount.UserInfo("kube-system", "namespace-controller", "")
- endpointController = serviceaccount.UserInfo("kube-system", "endpoint-controller", "")
- defaultSA = serviceaccount.UserInfo("default", "default", "")
- allUsers = []user.Info{anonymous, kubeproxy, ingress, kubelet, node, controller, scheduler, apiserver, autoscaler, npd, npdSA, namespaceController, endpointController, defaultSA}
- )
- // Resources for test cases
- var (
- nodes = resource("nodes")
- nodeStatus = resource("nodes", "", "", "status")
- endpoints = resource("endpoints", "default")
- sysEndpoints = resource("endpoints", "kube-system")
- services = resource("services", "default")
- serviceStatus = resource("services", "default", "", "status")
- configmaps = resource("configmaps", "default")
- sysConfigmaps = resource("configmaps", "kube-system")
- namespaces = resource("namespaces")
- namespaceStatus = resource("namespaces", "", "", "status")
- namespaceFinal = resource("namespaces", "", "", "finalize")
- podMetrics = resource("podmetrics", "default", "metrics.k8s.io")
- nodeMetrics = resource("nodemetrics", "", "metrics.k8s.io")
- pods = resource("pods", "default")
- podStatus = resource("pods", "default", "", "status")
- secrets = resource("secrets", "default")
- tokenReviews = resource("tokenreviews", "", "authentication.k8s.io")
- deployments = resource("deployments", "default", "apps")
- clusterRoles = resource("clusterroles", "", "rbac.authorization.k8s.io")
- events = resource("events", "default")
- foobars = resource("foos", "default", "example.com")
- foobarbaz = resource("foos", "default", "example.com", "baz")
- )
- // Aliases
- const (
- none = audit.LevelNone
- metadata = audit.LevelMetadata
- request = audit.LevelRequest
- response = audit.LevelRequestResponse
- )
- at := auditTester{
- T: t,
- checker: auditpolicy.NewChecker(policy),
- }
- at.testResources(none, kubeproxy, "watch", endpoints, sysEndpoints, services, serviceStatus)
- at.testResources(request, kubeproxy, "watch", nodes, pods)
- at.testResources(none, ingress, "get", sysConfigmaps)
- at.testResources(metadata, ingress, "get", configmaps)
- at.testResources(none, kubelet, node, "get", nodes, nodeStatus)
- at.testResources(metadata, kubelet, node, "get", sysConfigmaps, secrets)
- at.testResources(response, kubelet, node, "create", deployments, pods)
- at.testResources(none, controller, scheduler, endpointController, "get", "update", sysEndpoints)
- at.testResources(request, controller, scheduler, endpointController, "get", endpoints)
- at.testResources(response, controller, scheduler, endpointController, "update", endpoints)
- at.testResources(none, apiserver, "get", namespaces, namespaceStatus, namespaceFinal)
- at.testResources(metadata, apiserver, "get", "create", "update", sysConfigmaps, secrets)
- at.testResources(none, autoscaler, "get", "update", sysConfigmaps, sysEndpoints)
- at.testResources(metadata, autoscaler, "get", "update", configmaps)
- at.testResources(response, autoscaler, "update", endpoints)
- at.testResources(none, controller, "get", "list", podMetrics, nodeMetrics)
- at.testNonResources(none, allUsers, "/healthz", "/healthz/etcd", "/swagger-2.0.0.json", "/swagger-2.0.0.pb-v1.gz", "/version")
- at.testNonResources(metadata, allUsers, "/logs", "/openapi/v2", "/apis/policy", "/metrics", "/api")
- at.testResources(none, node, apiserver, defaultSA, anonymous, "get", "list", "create", "patch", "update", "delete", events)
- at.testResources(request, kubelet, node, npd, npdSA, "update", "patch", nodeStatus, podStatus)
- at.testResources(request, namespaceController, "deletecollection", pods, namespaces)
- at.testResources(metadata, defaultSA, anonymous, npd, namespaceController, "get", "create", "update", secrets, configmaps, sysConfigmaps, tokenReviews)
- at.testResources(request, defaultSA, anonymous, npd, namespaceController, "get", "list", "watch", sysEndpoints, podMetrics, pods, clusterRoles, deployments)
- at.testResources(response, defaultSA, anonymous, npd, namespaceController, "create", "update", "patch", "delete", sysEndpoints, podMetrics, pods, clusterRoles, deployments)
- at.testResources(metadata, defaultSA, anonymous, npd, namespaceController, "get", "list", "watch", "create", "update", "patch", "delete", foobars, foobarbaz)
- }
- type auditTester struct {
- *testing.T
- checker auditpolicy.Checker
- }
- func (t *auditTester) testResources(level audit.Level, usrVerbRes ...interface{}) {
- verbs := []string{}
- users := []user.Info{}
- resources := []Resource{}
- for _, arg := range usrVerbRes {
- switch v := arg.(type) {
- case string:
- verbs = append(verbs, v)
- case user.Info:
- users = append(users, v)
- case Resource:
- resources = append(resources, v)
- default:
- t.Fatalf("Invalid test argument: %+v", arg)
- }
- }
- require.NotEmpty(t, verbs, "testcases must have a verb")
- require.NotEmpty(t, users, "testcases must have a user")
- require.NotEmpty(t, resources, "resource testcases must have a resource")
- for _, usr := range users {
- for _, verb := range verbs {
- for _, res := range resources {
- attrs := &authorizer.AttributesRecord{
- User: usr,
- Verb: verb,
- Namespace: res.Namespace,
- APIGroup: res.Group,
- APIVersion: "v1",
- Resource: res.Resource,
- Subresource: res.Subresource,
- ResourceRequest: true,
- }
- t.expectLevel(level, attrs)
- }
- }
- }
- }
- func (t *auditTester) testNonResources(level audit.Level, users []user.Info, paths ...string) {
- for _, usr := range users {
- for _, verb := range []string{"get", "post"} {
- for _, path := range paths {
- attrs := &authorizer.AttributesRecord{
- User: usr,
- Verb: verb,
- ResourceRequest: false,
- Path: path,
- }
- t.expectLevel(level, attrs)
- }
- }
- }
- }
- func (t *auditTester) expectLevel(expected audit.Level, attrs authorizer.Attributes) {
- obj := attrs.GetPath()
- if attrs.IsResourceRequest() {
- obj = attrs.GetResource()
- if attrs.GetNamespace() != "" {
- obj = obj + ":" + attrs.GetNamespace()
- }
- }
- name := fmt.Sprintf("%s.%s.%s", attrs.GetUser().GetName(), attrs.GetVerb(), obj)
- checker := t.checker
- t.Run(name, func(t *testing.T) {
- level, stages := checker.LevelAndStages(attrs)
- assert.Equal(t, expected, level)
- if level != audit.LevelNone {
- assert.ElementsMatch(t, stages, []audit.Stage{audit.StageRequestReceived})
- }
- })
- }
- func newUserInfo(name string, groups ...string) user.Info {
- return &user.DefaultInfo{
- Name: name,
- Groups: groups,
- }
- }
- type Resource struct {
- Group, Resource, Subresource, Namespace string
- }
- func resource(kind string, nsGroupSub ...string) Resource {
- res := Resource{Resource: kind}
- if len(nsGroupSub) > 0 {
- res.Namespace = nsGroupSub[0]
- }
- if len(nsGroupSub) > 1 {
- res.Group = nsGroupSub[1]
- }
- if len(nsGroupSub) > 2 {
- res.Subresource = nsGroupSub[2]
- }
- return res
- }
|