mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 05:57:25 +00:00
Merge pull request #58807 from CaoShuFeng/audit_annotation_rbac
Automatic merge from submit-queue (batch tested with PRs 61183, 58807). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Add RBAC information to audit logs Depends on: https://github.com/kubernetes/kubernetes/pull/58806 **Release note**: ```release-note RBAC information is included in audit logs via audit.Event annotations: authorization.k8s.io/decision = {allow, forbid} authorization.k8s.io/reason = human-readable reason for the decision ```
This commit is contained in:
commit
58c0748b4d
@ -62,7 +62,7 @@ type authorizingVisitor struct {
|
|||||||
func (v *authorizingVisitor) visit(source fmt.Stringer, rule *rbac.PolicyRule, err error) bool {
|
func (v *authorizingVisitor) visit(source fmt.Stringer, rule *rbac.PolicyRule, err error) bool {
|
||||||
if rule != nil && RuleAllows(v.requestAttributes, rule) {
|
if rule != nil && RuleAllows(v.requestAttributes, rule) {
|
||||||
v.allowed = true
|
v.allowed = true
|
||||||
v.reason = fmt.Sprintf("allowed by %s", source.String())
|
v.reason = fmt.Sprintf("RBAC: allowed by %s", source.String())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -120,7 +120,7 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (aut
|
|||||||
|
|
||||||
reason := ""
|
reason := ""
|
||||||
if len(ruleCheckingVisitor.errors) > 0 {
|
if len(ruleCheckingVisitor.errors) > 0 {
|
||||||
reason = fmt.Sprintf("%v", utilerrors.NewAggregate(ruleCheckingVisitor.errors))
|
reason = fmt.Sprintf("RBAC: %v", utilerrors.NewAggregate(ruleCheckingVisitor.errors))
|
||||||
}
|
}
|
||||||
return authorizer.DecisionNoOpinion, reason, nil
|
return authorizer.DecisionNoOpinion, reason, nil
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/pborman/uuid:go_default_library",
|
"//vendor/github.com/pborman/uuid:go_default_library",
|
||||||
|
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||||
"//vendor/k8s.io/api/authentication/v1:go_default_library",
|
"//vendor/k8s.io/api/authentication/v1:go_default_library",
|
||||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
@ -737,6 +737,7 @@ func TestAudit(t *testing.T) {
|
|||||||
|
|
||||||
type fakeRequestContextMapper struct {
|
type fakeRequestContextMapper struct {
|
||||||
user *user.DefaultInfo
|
user *user.DefaultInfo
|
||||||
|
audit *auditinternal.Event
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *fakeRequestContextMapper) Get(req *http.Request) (request.Context, bool) {
|
func (m *fakeRequestContextMapper) Get(req *http.Request) (request.Context, bool) {
|
||||||
@ -744,6 +745,9 @@ func (m *fakeRequestContextMapper) Get(req *http.Request) (request.Context, bool
|
|||||||
if m.user != nil {
|
if m.user != nil {
|
||||||
ctx = request.WithUser(ctx, m.user)
|
ctx = request.WithUser(ctx, m.user)
|
||||||
}
|
}
|
||||||
|
if m.audit != nil {
|
||||||
|
ctx = request.WithAuditEvent(ctx, m.audit)
|
||||||
|
}
|
||||||
|
|
||||||
resolver := newTestRequestInfoResolver()
|
resolver := newTestRequestInfoResolver()
|
||||||
info, err := resolver.NewRequestInfo(req)
|
info, err := resolver.NewRequestInfo(req)
|
||||||
|
@ -23,11 +23,23 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apiserver/pkg/audit"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
||||||
"k8s.io/apiserver/pkg/endpoints/request"
|
"k8s.io/apiserver/pkg/endpoints/request"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Annotation key names set in advanced audit
|
||||||
|
decisionAnnotationKey = "authorization.k8s.io/decision"
|
||||||
|
reasonAnnotationKey = "authorization.k8s.io/reason"
|
||||||
|
|
||||||
|
// Annotation values set in advanced audit
|
||||||
|
decisionAllow = "allow"
|
||||||
|
decisionForbid = "forbid"
|
||||||
|
reasonError = "internal error"
|
||||||
|
)
|
||||||
|
|
||||||
// WithAuthorizationCheck passes all authorized requests on to handler, and returns a forbidden error otherwise.
|
// WithAuthorizationCheck passes all authorized requests on to handler, and returns a forbidden error otherwise.
|
||||||
func WithAuthorization(handler http.Handler, requestContextMapper request.RequestContextMapper, a authorizer.Authorizer, s runtime.NegotiatedSerializer) http.Handler {
|
func WithAuthorization(handler http.Handler, requestContextMapper request.RequestContextMapper, a authorizer.Authorizer, s runtime.NegotiatedSerializer) http.Handler {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
@ -40,6 +52,7 @@ func WithAuthorization(handler http.Handler, requestContextMapper request.Reques
|
|||||||
responsewriters.InternalError(w, req, errors.New("no context found for request"))
|
responsewriters.InternalError(w, req, errors.New("no context found for request"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ae := request.AuditEventFrom(ctx)
|
||||||
|
|
||||||
attributes, err := GetAuthorizerAttributes(ctx)
|
attributes, err := GetAuthorizerAttributes(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -49,15 +62,20 @@ func WithAuthorization(handler http.Handler, requestContextMapper request.Reques
|
|||||||
authorized, reason, err := a.Authorize(attributes)
|
authorized, reason, err := a.Authorize(attributes)
|
||||||
// an authorizer like RBAC could encounter evaluation errors and still allow the request, so authorizer decision is checked before error here.
|
// an authorizer like RBAC could encounter evaluation errors and still allow the request, so authorizer decision is checked before error here.
|
||||||
if authorized == authorizer.DecisionAllow {
|
if authorized == authorizer.DecisionAllow {
|
||||||
|
audit.LogAnnotation(ae, decisionAnnotationKey, decisionAllow)
|
||||||
|
audit.LogAnnotation(ae, reasonAnnotationKey, reason)
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
audit.LogAnnotation(ae, reasonAnnotationKey, reasonError)
|
||||||
responsewriters.InternalError(w, req, err)
|
responsewriters.InternalError(w, req, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.V(4).Infof("Forbidden: %#v, Reason: %q", req.RequestURI, reason)
|
glog.V(4).Infof("Forbidden: %#v, Reason: %q", req.RequestURI, reason)
|
||||||
|
audit.LogAnnotation(ae, decisionAnnotationKey, decisionForbid)
|
||||||
|
audit.LogAnnotation(ae, reasonAnnotationKey, reason)
|
||||||
responsewriters.Forbidden(ctx, attributes, w, req, reason, s)
|
responsewriters.Forbidden(ctx, attributes, w, req, reason, s)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,11 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
batch "k8s.io/api/batch/v1"
|
batch "k8s.io/api/batch/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
|
auditinternal "k8s.io/apiserver/pkg/apis/audit"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
||||||
"k8s.io/apiserver/pkg/endpoints/request"
|
"k8s.io/apiserver/pkg/endpoints/request"
|
||||||
@ -127,3 +131,65 @@ func TestGetAuthorizerAttributes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeAuthorizer struct {
|
||||||
|
decision authorizer.Decision
|
||||||
|
reason string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fakeAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
|
return f.decision, f.reason, f.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAuditAnnotation(t *testing.T) {
|
||||||
|
testcases := map[string]struct {
|
||||||
|
authorizer fakeAuthorizer
|
||||||
|
decisionAnnotation string
|
||||||
|
reasonAnnotation string
|
||||||
|
}{
|
||||||
|
"decision allow": {
|
||||||
|
fakeAuthorizer{
|
||||||
|
authorizer.DecisionAllow,
|
||||||
|
"RBAC: allowed to patch pod",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
"allow",
|
||||||
|
"RBAC: allowed to patch pod",
|
||||||
|
},
|
||||||
|
"decision forbid": {
|
||||||
|
fakeAuthorizer{
|
||||||
|
authorizer.DecisionDeny,
|
||||||
|
"RBAC: not allowed to patch pod",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
"forbid",
|
||||||
|
"RBAC: not allowed to patch pod",
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
fakeAuthorizer{
|
||||||
|
authorizer.DecisionNoOpinion,
|
||||||
|
"",
|
||||||
|
errors.New("can't parse user info"),
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
reasonError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme := runtime.NewScheme()
|
||||||
|
negotiatedSerializer := serializer.DirectCodecFactory{CodecFactory: serializer.NewCodecFactory(scheme)}
|
||||||
|
for k, tc := range testcases {
|
||||||
|
audit := &auditinternal.Event{Level: auditinternal.LevelMetadata}
|
||||||
|
handler := WithAuthorization(&fakeHTTPHandler{}, &fakeRequestContextMapper{
|
||||||
|
audit: audit,
|
||||||
|
}, tc.authorizer, negotiatedSerializer)
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", "/api/v1/namespaces/default/pods", nil)
|
||||||
|
req.RemoteAddr = "127.0.0.1"
|
||||||
|
handler.ServeHTTP(httptest.NewRecorder(), req)
|
||||||
|
assert.Equal(t, tc.decisionAnnotation, audit.Annotations[decisionAnnotationKey], k+": unexpected decision annotation")
|
||||||
|
assert.Equal(t, tc.reasonAnnotation, audit.Annotations[reasonAnnotationKey], k+": unexpected reason annotation")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -26,12 +26,14 @@ import (
|
|||||||
apiv1 "k8s.io/api/core/v1"
|
apiv1 "k8s.io/api/core/v1"
|
||||||
extensions "k8s.io/api/extensions/v1beta1"
|
extensions "k8s.io/api/extensions/v1beta1"
|
||||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
apiextensionclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||||
"k8s.io/apiextensions-apiserver/test/integration/testserver"
|
"k8s.io/apiextensions-apiserver/test/integration/testserver"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||||
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||||
|
|
||||||
@ -63,9 +65,19 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
|
|
||||||
config, err := framework.LoadConfig()
|
config, err := framework.LoadConfig()
|
||||||
framework.ExpectNoError(err, "failed to load config")
|
framework.ExpectNoError(err, "failed to load config")
|
||||||
apiExtensionClient, err := clientset.NewForConfig(config)
|
apiExtensionClient, err := apiextensionclientset.NewForConfig(config)
|
||||||
framework.ExpectNoError(err, "failed to initialize apiExtensionClient")
|
framework.ExpectNoError(err, "failed to initialize apiExtensionClient")
|
||||||
|
|
||||||
|
By("Creating a kubernetes client that impersonates an unauthorized anonymous user")
|
||||||
|
config, err = framework.LoadConfig()
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
config.Impersonate = restclient.ImpersonationConfig{
|
||||||
|
UserName: "system:anonymous",
|
||||||
|
Groups: []string{"system:unauthenticated"},
|
||||||
|
}
|
||||||
|
anonymousClient, err := clientset.NewForConfig(config)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
action func()
|
action func()
|
||||||
events []auditEvent
|
events []auditEvent
|
||||||
@ -118,6 +130,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequest,
|
v1beta1.LevelRequest,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -129,6 +142,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequest,
|
v1beta1.LevelRequest,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -140,6 +154,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequest,
|
v1beta1.LevelRequest,
|
||||||
v1beta1.StageResponseStarted,
|
v1beta1.StageResponseStarted,
|
||||||
@ -151,6 +166,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequest,
|
v1beta1.LevelRequest,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -162,6 +178,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequestResponse,
|
v1beta1.LevelRequestResponse,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -173,6 +190,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequestResponse,
|
v1beta1.LevelRequestResponse,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -184,6 +202,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequestResponse,
|
v1beta1.LevelRequestResponse,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -195,6 +214,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
"allow",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -239,6 +259,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequest,
|
v1beta1.LevelRequest,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -250,6 +271,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequest,
|
v1beta1.LevelRequest,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -261,6 +283,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequest,
|
v1beta1.LevelRequest,
|
||||||
v1beta1.StageResponseStarted,
|
v1beta1.StageResponseStarted,
|
||||||
@ -272,6 +295,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequest,
|
v1beta1.LevelRequest,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -283,6 +307,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequestResponse,
|
v1beta1.LevelRequestResponse,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -294,6 +319,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequestResponse,
|
v1beta1.LevelRequestResponse,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -305,6 +331,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelRequestResponse,
|
v1beta1.LevelRequestResponse,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -316,6 +343,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
"allow",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -366,6 +394,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -377,6 +406,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -388,6 +418,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseStarted,
|
v1beta1.StageResponseStarted,
|
||||||
@ -399,6 +430,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -410,6 +442,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -421,6 +454,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -432,6 +466,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -443,6 +478,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -492,6 +528,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -503,6 +540,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -514,6 +552,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseStarted,
|
v1beta1.StageResponseStarted,
|
||||||
@ -525,6 +564,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -536,6 +576,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -547,6 +588,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -558,6 +600,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
}, {
|
}, {
|
||||||
v1beta1.LevelMetadata,
|
v1beta1.LevelMetadata,
|
||||||
v1beta1.StageResponseComplete,
|
v1beta1.StageResponseComplete,
|
||||||
@ -569,6 +612,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
namespace,
|
namespace,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
"allow",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -590,6 +634,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
resource: "customresourcedefinitions",
|
resource: "customresourcedefinitions",
|
||||||
requestObject: true,
|
requestObject: true,
|
||||||
responseObject: true,
|
responseObject: true,
|
||||||
|
authorizeDecision: "allow",
|
||||||
}, {
|
}, {
|
||||||
level: v1beta1.LevelMetadata,
|
level: v1beta1.LevelMetadata,
|
||||||
stage: v1beta1.StageResponseComplete,
|
stage: v1beta1.StageResponseComplete,
|
||||||
@ -600,6 +645,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
resource: crdName,
|
resource: crdName,
|
||||||
requestObject: false,
|
requestObject: false,
|
||||||
responseObject: false,
|
responseObject: false,
|
||||||
|
authorizeDecision: "allow",
|
||||||
}, {
|
}, {
|
||||||
level: v1beta1.LevelRequestResponse,
|
level: v1beta1.LevelRequestResponse,
|
||||||
stage: v1beta1.StageResponseComplete,
|
stage: v1beta1.StageResponseComplete,
|
||||||
@ -610,6 +656,7 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
resource: "customresourcedefinitions",
|
resource: "customresourcedefinitions",
|
||||||
requestObject: false,
|
requestObject: false,
|
||||||
responseObject: true,
|
responseObject: true,
|
||||||
|
authorizeDecision: "allow",
|
||||||
}, {
|
}, {
|
||||||
level: v1beta1.LevelMetadata,
|
level: v1beta1.LevelMetadata,
|
||||||
stage: v1beta1.StageResponseComplete,
|
stage: v1beta1.StageResponseComplete,
|
||||||
@ -620,11 +667,45 @@ var _ = SIGDescribe("Advanced Audit", func() {
|
|||||||
resource: crdName,
|
resource: crdName,
|
||||||
requestObject: false,
|
requestObject: false,
|
||||||
responseObject: false,
|
responseObject: false,
|
||||||
|
authorizeDecision: "allow",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test authorizer annotations, RBAC is required.
|
||||||
|
annotationTestCases := []struct {
|
||||||
|
action func()
|
||||||
|
events []auditEvent
|
||||||
|
}{
|
||||||
|
|
||||||
|
// get a pod with unauthorized user
|
||||||
|
{
|
||||||
|
func() {
|
||||||
|
_, err := anonymousClient.CoreV1().Pods(namespace).Get("another-audit-pod", metav1.GetOptions{})
|
||||||
|
expectForbidden(err)
|
||||||
|
},
|
||||||
|
[]auditEvent{
|
||||||
|
{
|
||||||
|
level: v1beta1.LevelRequest,
|
||||||
|
stage: v1beta1.StageResponseComplete,
|
||||||
|
requestURI: fmt.Sprintf("/api/v1/namespaces/%s/pods/another-audit-pod", namespace),
|
||||||
|
verb: "get",
|
||||||
|
code: 403,
|
||||||
|
user: auditTestUser,
|
||||||
|
resource: "pods",
|
||||||
|
namespace: namespace,
|
||||||
|
requestObject: false,
|
||||||
|
responseObject: false,
|
||||||
|
authorizeDecision: "forbid",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if framework.IsRBACEnabled(f) {
|
||||||
|
testCases = append(testCases, annotationTestCases...)
|
||||||
|
}
|
||||||
expectedEvents := []auditEvent{}
|
expectedEvents := []auditEvent{}
|
||||||
for _, t := range testCases {
|
for _, t := range testCases {
|
||||||
t.action()
|
t.action()
|
||||||
@ -657,6 +738,7 @@ type auditEvent struct {
|
|||||||
namespace string
|
namespace string
|
||||||
requestObject bool
|
requestObject bool
|
||||||
responseObject bool
|
responseObject bool
|
||||||
|
authorizeDecision string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search the audit log for the expected audit lines.
|
// Search the audit log for the expected audit lines.
|
||||||
@ -725,5 +807,6 @@ func parseAuditLine(line string) (auditEvent, error) {
|
|||||||
if e.RequestObject != nil {
|
if e.RequestObject != nil {
|
||||||
event.requestObject = true
|
event.requestObject = true
|
||||||
}
|
}
|
||||||
|
event.authorizeDecision = e.Annotations["authorization.k8s.io/decision"]
|
||||||
return event, nil
|
return event, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user