diff --git a/src/dsmlp/app/validator.py b/src/dsmlp/app/validator.py index df2348b..61e875a 100644 --- a/src/dsmlp/app/validator.py +++ b/src/dsmlp/app/validator.py @@ -46,6 +46,7 @@ class Object: @dataclass_json @dataclass class Request: + uid: str namespace: str object: Object @@ -67,9 +68,11 @@ def __init__(self, awsed: AwsedClient, kube: KubeClient, logger: Logger) -> None self.kube = kube self.logger = logger - def validate_request(self, request): - self.logger.debug("request=" + json.dumps(request, indent=2)) - review: AdmissionReview = AdmissionReview.from_dict(request) + def validate_request(self, request_json): + self.logger.debug("request=" + json.dumps(request_json, indent=2)) + review: AdmissionReview = AdmissionReview.from_dict(request_json) + request: Request = review.request + request_uid = request.uid namespace_name = review.request.namespace username = namespace_name self.logger.info(f"Validating request namespace={namespace_name}") @@ -77,12 +80,13 @@ def validate_request(self, request): try: namespace = self.kube.get_namespace(namespace_name) except UnsuccessfulRequest: - return self.admission_response(False, f"Denied request username={username} namespace={namespace_name}") + return self.admission_response( + request_uid, False, f"Denied request username={username} namespace={namespace_name}") labels = namespace.labels if not 'k8s-sync' in labels: self.logger.info(f"Allowed namespace={namespace_name}") - return self.admission_response(True, "Allowed") + return self.admission_response(request_uid, True, "Allowed") user = self.awsed.describe_user(username) user_uid = user.uid @@ -94,7 +98,7 @@ def validate_request(self, request): if user_uid != uid: self.logger.info( f"Denied request username={username} namespace={namespace_name} uid={user_uid} spec.securityContext.runAsUser={uid}") - return self.admission_response(False, f"{username} is not allowed to use uid {uid}") + return self.admission_response(request_uid, False, f"{username} is not allowed to use uid {uid}") container_uids = [container.securityContext.runAsUser for container in spec.containers if container.securityContext is not None and container.securityContext.runAsUser is not None] @@ -103,9 +107,15 @@ def validate_request(self, request): if user_uid != uid: self.logger.info( "Denied request username=user2 namespace=user2 uid=2 spec.containers[0].securityContext.runAsUser=3") - return self.admission_response(False, f"{username} is not allowed to use uid {uid}") - - return self.admission_response(True, "Allowed") - - def admission_response(self, allowed, message): - return {"response": {"allowed": allowed, "status": {"message": message}}} + return self.admission_response(request_uid, False, f"{username} is not allowed to use uid {uid}") + + return self.admission_response(request_uid, True, "Allowed") + + def admission_response(self, uid, allowed, message): + return { + "response": { + "uid": uid, + "allowed": allowed, + "status": {"message": message} + } + } diff --git a/tests/app/test_validator.py b/tests/app/test_validator.py index bd47562..c16f2e4 100644 --- a/tests/app/test_validator.py +++ b/tests/app/test_validator.py @@ -25,6 +25,7 @@ def test_pod_security_context(self): response = self.when_validate( { "request": { + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "namespace": "user1", "object": { "spec": { @@ -38,7 +39,8 @@ def test_pod_security_context(self): } ) - assert_that(response, equal_to({"response": {"allowed": True, "status": {"message": "Allowed"}}})) + assert_that(response, equal_to( + {"response": {"uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "allowed": True, "status": {"message": "Allowed"}}})) assert_that(self.logger.messages, has_item("INFO Validating request namespace=user1")) def test_security_context(self): @@ -48,6 +50,7 @@ def test_security_context(self): response = self.when_validate( { "request": { + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "namespace": "user1", "object": { "spec": { @@ -67,7 +70,8 @@ def test_security_context(self): } ) - assert_that(response, equal_to({"response": {"allowed": True, "status": {"message": "Allowed"}}})) + assert_that(response, equal_to( + {"response": {"uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "allowed": True, "status": {"message": "Allowed"}}})) assert_that(self.logger.messages, has_item("INFO Validating request namespace=user1")) def test_deny_security_context(self): @@ -77,6 +81,7 @@ def test_deny_security_context(self): response = self.when_validate( { "request": { + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "namespace": "user2", "object": { "spec": { @@ -87,8 +92,8 @@ def test_deny_security_context(self): }} ) - assert_that(response, equal_to({"response": {"allowed": False, "status": { - "message": "user2 is not allowed to use uid 3"}}})) + assert_that(response, equal_to({"response": {"uid": "705ab4f5-6393-11e8-b7cc-42010a800002", + "allowed": False, "status": {"message": "user2 is not allowed to use uid 3"}}})) assert_that(self.logger.messages, has_item( "INFO Denied request username=user2 namespace=user2 uid=2 spec.securityContext.runAsUser=3")) @@ -99,6 +104,7 @@ def test_deny_unknown_user(self): response = self.when_validate( { "request": { + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "namespace": "user2", "object": { "spec": { @@ -109,8 +115,9 @@ def test_deny_unknown_user(self): }} ) - assert_that(response, equal_to({"response": {"allowed": False, "status": { - "message": "Denied request username=user2 namespace=user2"}}})) + assert_that(response, equal_to({"response": {"uid": "705ab4f5-6393-11e8-b7cc-42010a800002", + "allowed": False, "status": { + "message": "Denied request username=user2 namespace=user2"}}})) # assert_that(self.logger.messages, has_item( # "INFO Denied request username=user2 namespace=user2")) @@ -121,6 +128,7 @@ def test_deny_pod_security_context(self): response = self.when_validate( { "request": { + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "namespace": "user2", "object": { "kind": "Pod", @@ -136,8 +144,8 @@ def test_deny_pod_security_context(self): }} ) - assert_that(response, equal_to({"response": {"allowed": False, "status": { - "message": "user2 is not allowed to use uid 3"}}})) + assert_that(response, equal_to({"response": {"uid": "705ab4f5-6393-11e8-b7cc-42010a800002", + "allowed": False, "status": {"message": "user2 is not allowed to use uid 3"}}})) assert_that(self.logger.messages, has_item(equal_to( "INFO Denied request username=user2 namespace=user2 uid=2 spec.containers[0].securityContext.runAsUser=3"))) @@ -147,6 +155,7 @@ def test_unlabelled_namespace_can_use_any_uid(self): response = self.when_validate( { "request": { + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "namespace": "kube-system", "object": { # "kind": "Pod", @@ -163,8 +172,8 @@ def test_unlabelled_namespace_can_use_any_uid(self): } ) - assert_that(response, equal_to({"response": {"allowed": True, "status": { - "message": "Allowed"}}})) + assert_that(response, equal_to( + {"response": {"uid": "705ab4f5-6393-11e8-b7cc-42010a800002", "allowed": True, "status": {"message": "Allowed"}}})) assert_that(self.logger.messages, has_item( "INFO Allowed namespace=kube-system"))