From 5121fa0a27b95a7239dcdd53391b1cbc38ca814b Mon Sep 17 00:00:00 2001 From: John Howard Date: Fri, 18 Oct 2024 13:20:25 -0700 Subject: [PATCH 1/3] AuthorizationPolicy: add `serviceAccounts` field This is a minor implementation complexity in favor of a dramatic simplification to usage of Istio authorization. Today, if a user wants to dive into zero-trust 101, they are presented with a requirement to set `principals`: `A list of peer identities derived from the peer certificate`, and write `/ns//sa/`. This simple sentance is a huge cognitive overload for users in my experience working with users, and unnecesarily pushes SPIFFE, trust domains, and other unneccesary concepts onto users. Additionally, the requirement to set 'trust domain', which is overwhelmingly not desired by users who just want SA auth, leads to all sorts of wonky workarounds in Istio like `cluster.local` being a magic value. Instead, we just add a SA field directly. This takes the format `ns/sa`, as you cannot safely reference a SA without a namespace field as well. Note we do this, rather than just require you to set 'service account' and 'namespace' as individual fields, since you could have `namespace=[a,b],sa=[d,e]` which is ambiguous. If this is directionally approved, I will add some more documentation and CEL validation and testing. --- kubernetes/customresourcedefinitions.gen.yaml | 20 ++++ security/v1beta1/authorization_policy.pb.go | 99 ++++++++++++------- security/v1beta1/authorization_policy.pb.html | 26 +++++ security/v1beta1/authorization_policy.proto | 13 +++ 4 files changed, 124 insertions(+), 34 deletions(-) diff --git a/kubernetes/customresourcedefinitions.gen.yaml b/kubernetes/customresourcedefinitions.gen.yaml index 9777d4595b0..6674d687f9b 100644 --- a/kubernetes/customresourcedefinitions.gen.yaml +++ b/kubernetes/customresourcedefinitions.gen.yaml @@ -14578,6 +14578,11 @@ spec: items: type: string type: array + notServiceAccounts: + description: Optional. + items: + type: string + type: array principals: description: Optional. items: @@ -14593,6 +14598,11 @@ spec: items: type: string type: array + serviceAccounts: + description: Optional. + items: + type: string + type: array type: object type: object type: array @@ -14931,6 +14941,11 @@ spec: items: type: string type: array + notServiceAccounts: + description: Optional. + items: + type: string + type: array principals: description: Optional. items: @@ -14946,6 +14961,11 @@ spec: items: type: string type: array + serviceAccounts: + description: Optional. + items: + type: string + type: array type: object type: object type: array diff --git a/security/v1beta1/authorization_policy.pb.go b/security/v1beta1/authorization_policy.pb.go index edb36e3e5b6..2b3c0c66d55 100644 --- a/security/v1beta1/authorization_policy.pb.go +++ b/security/v1beta1/authorization_policy.pb.go @@ -615,6 +615,8 @@ type Source struct { // `"/ns//sa/"`, for example, `"cluster.local/ns/default/sa/productpage"`. // This field requires mTLS enabled and is the same as the `source.principal` attribute. // + // Usage of `serviceAccounts` is typically simpler and offers the same functionality. + // // If not set, any principal is allowed. Principals []string `protobuf:"bytes,1,rep,name=principals,proto3" json:"principals,omitempty"` // Optional. A list of negative match of peer identities. @@ -634,6 +636,15 @@ type Source struct { Namespaces []string `protobuf:"bytes,3,rep,name=namespaces,proto3" json:"namespaces,omitempty"` // Optional. A list of negative match of namespaces. NotNamespaces []string `protobuf:"bytes,7,rep,name=not_namespaces,json=notNamespaces,proto3" json:"not_namespaces,omitempty"` + // Optional. A list of service accounts derived from the peer certificate. + // This field requires mTLS enabled and is the same as the `source.serviceaccount` attribute. + // + // This takes the format `/`. + // + // If not set, any service account is allowed. + ServiceAccounts []string `protobuf:"bytes,11,rep,name=service_accounts,json=serviceAccounts,proto3" json:"service_accounts,omitempty"` + // Optional. A list of negative match of service accounts. + NotServiceAccounts []string `protobuf:"bytes,12,rep,name=not_service_accounts,json=notServiceAccounts,proto3" json:"not_service_accounts,omitempty"` // Optional. A list of IP blocks, populated from the source address of the IP packet. Single IP (e.g. `203.0.113.4`) and // CIDR (e.g. `203.0.113.0/24`) are supported. This is the same as the `source.ip` attribute. // @@ -726,6 +737,20 @@ func (x *Source) GetNotNamespaces() []string { return nil } +func (x *Source) GetServiceAccounts() []string { + if x != nil { + return x.ServiceAccounts + } + return nil +} + +func (x *Source) GetNotServiceAccounts() []string { + if x != nil { + return x.NotServiceAccounts + } + return nil +} + func (x *Source) GetIpBlocks() []string { if x != nil { return x.IpBlocks @@ -1175,7 +1200,7 @@ var file_security_v1beta1_authorization_policy_proto_rawDesc = []byte{ 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x69, 0x73, 0x74, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x97, 0x03, + 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xf4, 0x03, 0x0a, 0x06, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x5f, @@ -1191,39 +1216,45 @@ var file_security_v1beta1_authorization_policy_proto_rawDesc = []byte{ 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x6f, - 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, - 0x70, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, - 0x69, 0x70, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x74, 0x5f, - 0x69, 0x70, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0b, 0x6e, 0x6f, 0x74, 0x49, 0x70, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x28, 0x0a, 0x10, - 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x69, 0x70, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x70, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2f, 0x0a, 0x14, 0x6e, 0x6f, 0x74, 0x5f, 0x72, 0x65, - 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x69, 0x70, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x0a, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x6e, 0x6f, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, - 0x70, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x22, 0xdf, 0x01, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6e, - 0x6f, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, - 0x6e, 0x6f, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x6f, 0x72, 0x74, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x1b, - 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, - 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x65, 0x74, - 0x68, 0x6f, 0x64, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x6f, 0x74, 0x4d, - 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1b, 0x0a, 0x09, - 0x6e, 0x6f, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x6e, 0x6f, 0x74, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0x5a, 0x0a, 0x09, 0x43, 0x6f, 0x6e, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, - 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x74, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x1f, 0x5a, 0x1d, 0x69, 0x73, 0x74, 0x69, 0x6f, 0x2e, 0x69, - 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, + 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x6e, 0x6f, 0x74, 0x5f, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x0c, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x6e, 0x6f, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x70, 0x5f, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x70, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x74, 0x5f, 0x69, 0x70, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x6f, + 0x74, 0x49, 0x70, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x5f, 0x69, 0x70, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x09, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x70, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x12, 0x2f, 0x0a, 0x14, 0x6e, 0x6f, 0x74, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, + 0x65, 0x5f, 0x69, 0x70, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x11, 0x6e, 0x6f, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x70, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x73, 0x22, 0xdf, 0x01, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, 0x5f, + 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x74, + 0x48, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6e, + 0x6f, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x6e, 0x6f, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x6f, 0x74, 0x4d, 0x65, 0x74, 0x68, + 0x6f, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x74, + 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, + 0x74, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0x5a, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x42, 0x1f, 0x5a, 0x1d, 0x69, 0x73, 0x74, 0x69, 0x6f, 0x2e, 0x69, 0x6f, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/security/v1beta1/authorization_policy.pb.html b/security/v1beta1/authorization_policy.pb.html index e72d57260c8..f92a60afcfa 100644 --- a/security/v1beta1/authorization_policy.pb.html +++ b/security/v1beta1/authorization_policy.pb.html @@ -376,6 +376,7 @@

Source

Optional. A list of peer identities derived from the peer certificate. The peer identity is in the format of "<TRUST_DOMAIN>/ns/<NAMESPACE>/sa/<SERVICE_ACCOUNT>", for example, "cluster.local/ns/default/sa/productpage". This field requires mTLS enabled and is the same as the source.principal attribute.

+

Usage of serviceAccounts is typically simpler and offers the same functionality.

If not set, any principal is allowed.

@@ -438,6 +439,31 @@

Source

Optional. A list of negative match of namespaces.

+ + +No + + + +serviceAccounts +string[] + +

Optional. A list of service accounts derived from the peer certificate. +This field requires mTLS enabled and is the same as the source.serviceaccount attribute.

+

This takes the format <namespace>/<serviceaccount>.

+

If not set, any service account is allowed.

+ + + +No + + + +notServiceAccounts +string[] + +

Optional. A list of negative match of service accounts.

+ No diff --git a/security/v1beta1/authorization_policy.proto b/security/v1beta1/authorization_policy.proto index 3bb1049b6ea..4893471f677 100644 --- a/security/v1beta1/authorization_policy.proto +++ b/security/v1beta1/authorization_policy.proto @@ -428,6 +428,8 @@ message Source { // `"/ns//sa/"`, for example, `"cluster.local/ns/default/sa/productpage"`. // This field requires mTLS enabled and is the same as the `source.principal` attribute. // + // Usage of `serviceAccounts` is typically simpler and offers the same functionality. + // // If not set, any principal is allowed. repeated string principals = 1; @@ -453,6 +455,17 @@ message Source { // Optional. A list of negative match of namespaces. repeated string not_namespaces = 7; + // Optional. A list of service accounts derived from the peer certificate. + // This field requires mTLS enabled and is the same as the `source.serviceaccount` attribute. + // + // This takes the format `/`. + // + // If not set, any service account is allowed. + repeated string service_accounts = 11; + + // Optional. A list of negative match of service accounts. + repeated string not_service_accounts = 12; + // Optional. A list of IP blocks, populated from the source address of the IP packet. Single IP (e.g. `203.0.113.4`) and // CIDR (e.g. `203.0.113.0/24`) are supported. This is the same as the `source.ip` attribute. // From 15e93f53bf9aa0d8144e331e7e705ea550628c0d Mon Sep 17 00:00:00 2001 From: John Howard Date: Mon, 28 Oct 2024 13:31:59 -0700 Subject: [PATCH 2/3] Tests and validation --- kubernetes/customresourcedefinitions.gen.yaml | 26 ++++++ security/v1/authorization_policy_alias.gen.go | 1 + security/v1beta1/authorization_policy.pb.go | 13 +++ security/v1beta1/authorization_policy.pb.html | 3 + security/v1beta1/authorization_policy.proto | 13 +++ tests/testdata/authz-invalid.yaml | 23 +++++ tests/testdata/authz-valid.yaml | 88 +++++++++++++++++++ 7 files changed, 167 insertions(+) create mode 100644 tests/testdata/authz-invalid.yaml create mode 100644 tests/testdata/authz-valid.yaml diff --git a/kubernetes/customresourcedefinitions.gen.yaml b/kubernetes/customresourcedefinitions.gen.yaml index 6674d687f9b..bb6cca82a5b 100644 --- a/kubernetes/customresourcedefinitions.gen.yaml +++ b/kubernetes/customresourcedefinitions.gen.yaml @@ -14581,7 +14581,9 @@ spec: notServiceAccounts: description: Optional. items: + maxLength: 320 type: string + maxItems: 16 type: array principals: description: Optional. @@ -14601,10 +14603,20 @@ spec: serviceAccounts: description: Optional. items: + maxLength: 320 type: string + maxItems: 16 type: array type: object + x-kubernetes-validations: + - message: Cannot set serviceAccounts with namespaces + or principals + rule: '(has(self.serviceAccounts) || has(self.notServiceAccounts)) + ? (!has(self.principals) && !has(self.notPrincipals) + && !has(self.namespaces) && !has(self.notNamespaces)) + : true' type: object + maxItems: 512 type: array to: description: Optional. @@ -14678,6 +14690,7 @@ spec: type: object type: array type: object + maxItems: 512 type: array selector: description: Optional. @@ -14944,7 +14957,9 @@ spec: notServiceAccounts: description: Optional. items: + maxLength: 320 type: string + maxItems: 16 type: array principals: description: Optional. @@ -14964,10 +14979,20 @@ spec: serviceAccounts: description: Optional. items: + maxLength: 320 type: string + maxItems: 16 type: array type: object + x-kubernetes-validations: + - message: Cannot set serviceAccounts with namespaces + or principals + rule: '(has(self.serviceAccounts) || has(self.notServiceAccounts)) + ? (!has(self.principals) && !has(self.notPrincipals) + && !has(self.namespaces) && !has(self.notNamespaces)) + : true' type: object + maxItems: 512 type: array to: description: Optional. @@ -15041,6 +15066,7 @@ spec: type: object type: array type: object + maxItems: 512 type: array selector: description: Optional. diff --git a/security/v1/authorization_policy_alias.gen.go b/security/v1/authorization_policy_alias.gen.go index d018f0fba96..b01c993ab2f 100644 --- a/security/v1/authorization_policy_alias.gen.go +++ b/security/v1/authorization_policy_alias.gen.go @@ -112,6 +112,7 @@ type Rule_To = v1beta1.Rule_To // namespaces: ["prod", "test"] // notIpBlocks: ["203.0.113.4"] // ``` +// +kubebuilder:validation:XValidation:message="Cannot set serviceAccounts with namespaces or principals",rule="(has(self.serviceAccounts) || has(self.notServiceAccounts)) ? (!has(self.principals) && !has(self.notPrincipals) && !has(self.namespaces) && !has(self.notNamespaces)) : true" type Source = v1beta1.Source // Operation specifies the operations of a request. Fields in the operation are diff --git a/security/v1beta1/authorization_policy.pb.go b/security/v1beta1/authorization_policy.pb.go index 2b3c0c66d55..5ebe984e9c6 100644 --- a/security/v1beta1/authorization_policy.pb.go +++ b/security/v1beta1/authorization_policy.pb.go @@ -416,6 +416,7 @@ type AuthorizationPolicy struct { // // If not set, the match will never occur. This is equivalent to setting a default of deny for the target workloads if // the action is ALLOW. + // +kubebuilder:validation:MaxItems=512 Rules []*Rule `protobuf:"bytes,2,rep,name=rules,proto3" json:"rules,omitempty"` // Optional. The action to take if the request is matched with the rules. Default is ALLOW if not specified. Action AuthorizationPolicy_Action `protobuf:"varint,3,opt,name=action,proto3,enum=istio.security.v1beta1.AuthorizationPolicy_Action" json:"action,omitempty"` @@ -533,6 +534,7 @@ type Rule struct { // Optional. `from` specifies the source of a request. // // If not set, any source is allowed. + // +kubebuilder:validation:MaxItems=512 From []*Rule_From `protobuf:"bytes,1,rep,name=from,proto3" json:"from,omitempty"` // Optional. `to` specifies the operation of a request. // @@ -606,6 +608,7 @@ func (x *Rule) GetWhen() []*Condition { // namespaces: ["prod", "test"] // notIpBlocks: ["203.0.113.4"] // ``` +// +kubebuilder:validation:XValidation:message="Cannot set serviceAccounts with namespaces or principals",rule="(has(self.serviceAccounts) || has(self.notServiceAccounts)) ? (!has(self.principals) && !has(self.notPrincipals) && !has(self.namespaces) && !has(self.notNamespaces)) : true" type Source struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -642,8 +645,18 @@ type Source struct { // This takes the format `/`. // // If not set, any service account is allowed. + // + // No form of wildcard (`*`) is allowed. + // +protoc-gen-crd:list-value-validation:MaxLength=320 + // +kubebuilder:validation:MaxItems=16 ServiceAccounts []string `protobuf:"bytes,11,rep,name=service_accounts,json=serviceAccounts,proto3" json:"service_accounts,omitempty"` // Optional. A list of negative match of service accounts. + // + // This takes the format `/`. + // + // No form of wildcard (`*`) is allowed. + // +protoc-gen-crd:list-value-validation:MaxLength=320 + // +kubebuilder:validation:MaxItems=16 NotServiceAccounts []string `protobuf:"bytes,12,rep,name=not_service_accounts,json=notServiceAccounts,proto3" json:"not_service_accounts,omitempty"` // Optional. A list of IP blocks, populated from the source address of the IP packet. Single IP (e.g. `203.0.113.4`) and // CIDR (e.g. `203.0.113.0/24`) are supported. This is the same as the `source.ip` attribute. diff --git a/security/v1beta1/authorization_policy.pb.html b/security/v1beta1/authorization_policy.pb.html index f92a60afcfa..96538605376 100644 --- a/security/v1beta1/authorization_policy.pb.html +++ b/security/v1beta1/authorization_policy.pb.html @@ -452,6 +452,7 @@

Source

This field requires mTLS enabled and is the same as the source.serviceaccount attribute.

This takes the format <namespace>/<serviceaccount>.

If not set, any service account is allowed.

+

No form of wildcard (*) is allowed.

@@ -463,6 +464,8 @@

Source

string[]

Optional. A list of negative match of service accounts.

+

This takes the format <namespace>/<serviceaccount>.

+

No form of wildcard (*) is allowed.

diff --git a/security/v1beta1/authorization_policy.proto b/security/v1beta1/authorization_policy.proto index 4893471f677..a3325c550ac 100644 --- a/security/v1beta1/authorization_policy.proto +++ b/security/v1beta1/authorization_policy.proto @@ -308,6 +308,7 @@ message AuthorizationPolicy { // // If not set, the match will never occur. This is equivalent to setting a default of deny for the target workloads if // the action is ALLOW. + // +kubebuilder:validation:MaxItems=512 repeated Rule rules = 2; // Action specifies the operation to take. @@ -393,6 +394,7 @@ message Rule { // Optional. `from` specifies the source of a request. // // If not set, any source is allowed. + // +kubebuilder:validation:MaxItems=512 repeated From from = 1; // To includes a list of operations. @@ -423,6 +425,7 @@ message Rule { // namespaces: ["prod", "test"] // notIpBlocks: ["203.0.113.4"] // ``` +// +kubebuilder:validation:XValidation:message="Cannot set serviceAccounts with namespaces or principals",rule="(has(self.serviceAccounts) || has(self.notServiceAccounts)) ? (!has(self.principals) && !has(self.notPrincipals) && !has(self.namespaces) && !has(self.notNamespaces)) : true" message Source { // Optional. A list of peer identities derived from the peer certificate. The peer identity is in the format of // `"/ns//sa/"`, for example, `"cluster.local/ns/default/sa/productpage"`. @@ -461,9 +464,19 @@ message Source { // This takes the format `/`. // // If not set, any service account is allowed. + // + // No form of wildcard (`*`) is allowed. + // +protoc-gen-crd:list-value-validation:MaxLength=320 + // +kubebuilder:validation:MaxItems=16 repeated string service_accounts = 11; // Optional. A list of negative match of service accounts. + // + // This takes the format `/`. + // + // No form of wildcard (`*`) is allowed. + // +protoc-gen-crd:list-value-validation:MaxLength=320 + // +kubebuilder:validation:MaxItems=16 repeated string not_service_accounts = 12; // Optional. A list of IP blocks, populated from the source address of the IP packet. Single IP (e.g. `203.0.113.4`) and diff --git a/tests/testdata/authz-invalid.yaml b/tests/testdata/authz-invalid.yaml new file mode 100644 index 00000000000..e3c5b9b5f15 --- /dev/null +++ b/tests/testdata/authz-invalid.yaml @@ -0,0 +1,23 @@ +_err: Cannot set serviceAccounts with namespaces or principals +apiVersion: security.istio.io/v1 +kind: AuthorizationPolicy +metadata: + name: service-account-and-namespace +spec: + rules: + - from: + - source: + serviceAccounts: ["bar/sa"] + namespaces: ["bar"] +--- +_err: Cannot set serviceAccounts with namespaces or principals +apiVersion: security.istio.io/v1 +kind: AuthorizationPolicy +metadata: + name: service-account-and-namespace-principal +spec: + rules: + - from: + - source: + serviceAccounts: ["baz/sa"] + principals: ["bar"] diff --git a/tests/testdata/authz-valid.yaml b/tests/testdata/authz-valid.yaml new file mode 100644 index 00000000000..a3a1bba3207 --- /dev/null +++ b/tests/testdata/authz-valid.yaml @@ -0,0 +1,88 @@ +apiVersion: security.istio.io/v1 +kind: AuthorizationPolicy +metadata: + name: full +spec: + selector: + matchLabels: + app: httpbin + rules: + - from: + - source: + principals: ["principal", "principal-prefix-*", "*-suffix-principal", "*"] + requestPrincipals: ["requestPrincipals", "requestPrincipals-prefix-*", "*-suffix-requestPrincipals", "*"] + namespaces: ["ns", "ns-prefix-*", "*-ns-suffix", "*"] + ipBlocks: ["1.2.3.4", "5.6.0.0/16"] + remoteIpBlocks: ["1.2.3.4", "5.6.0.0/16"] + notPrincipals: ["not-principal", "not-principal-prefix-*", "*-not-suffix-principal", "*"] + notRequestPrincipals: ["not-requestPrincipals", "not-requestPrincipals-prefix-*", "*-not-suffix-requestPrincipals", "*"] + notNamespaces: ["not-ns", "not-ns-prefix-*", "*-not-ns-suffix", "*"] + notIpBlocks: ["9.0.0.1", "9.2.0.0/16"] + notRemoteIpBlocks: ["9.0.0.1", "9.2.0.0/16"] + to: + - operation: + methods: ["method", "method-prefix-*", "*-suffix-method", "*"] + hosts: ["exact.com", "*.suffix.com", "prefix.*", "*"] + ports: ["80", "90"] + paths: ["/exact", "/prefix/*", "*/suffix", "*", "/path/template/{*}", "/{**}/path/template"] + notMethods: ["not-method", "not-method-prefix-*", "*-not-suffix-method", "*"] + notHosts: ["not-exact.com", "*.not-suffix.com", "not-prefix.*", "*"] + notPorts: ["8000", "9000"] + notPaths: ["/not-exact", "/not-prefix/*", "*/not-suffix", "*", "/not-path/template/{*}", "/{**}/not-path/template"] + when: + - key: "request.headers[X-header]" + values: ["header", "header-prefix-*", "*-suffix-header", "*"] + notValues: ["not-header", "not-header-prefix-*", "*-not-suffix-header", "*"] + - key: "source.ip" + values: ["10.10.10.10", "192.168.10.0/24"] + notValues: ["90.10.10.10", "90.168.10.0/24"] + - key: "remote.ip" + values: ["10.10.10.10", "192.168.10.0/24"] + notValues: ["90.10.10.10", "90.168.10.0/24"] + - key: "source.namespace" + values: ["ns", "ns-prefix-*", "*-ns-suffix", "*"] + notValues: ["not-ns", "not-ns-prefix-*", "*-not-ns-suffix", "*"] + - key: "source.principal" + values: ["principal", "principal-prefix-*", "*-suffix-principal", "*"] + notValues: ["not-principal", "not-principal-prefix-*", "*-not-suffix-principal", "*"] + - key: "request.auth.principal" + values: ["requestPrincipals", "requestPrincipals-prefix-*", "*-suffix-requestPrincipals", "*", "https://example.com/*"] + notValues: ["not-requestPrincipals", "not-requestPrincipals-prefix-*", "*-not-suffix-requestPrincipals", "*"] + - key: "request.auth.audiences" + values: ["audiences", "audiences-prefix-*", "*-suffix-audiences", "*"] + notValues: ["not-audiences", "not-audiences-prefix-*", "*-not-suffix-audiences", "*"] + - key: "request.auth.presenter" + values: ["presenter", "presenter-prefix-*", "*-suffix-presenter", "*"] + notValues: ["not-presenter", "not-presenter-prefix-*", "*-not-suffix-presenter", "*"] + - key: "request.auth.claims[iss]" + values: ["iss", "iss-prefix-*", "*-suffix-iss", "*"] + notValues: ["not-iss", "not-iss-prefix-*", "*-not-suffix-iss", "*"] + - key: "request.auth.claims[nested1][nested2]" + values: ["nested", "nested-prefix-*", "*-suffix-nested", "*"] + notValues: ["not-nested", "not-nested-prefix-*", "*-not-suffix-nested", "*"] + - key: "destination.ip" + values: ["10.10.10.10", "192.168.10.0/24"] + notValues: ["90.10.10.10", "90.168.10.0/24"] + - key: "destination.port" + values: ["91", "92"] + notValues: ["9001", "9002"] + - key: "connection.sni" + values: ["exact.com", "*.suffix.com", "prefix.*", "*"] + notValues: ["not-exact.com", "*.not-suffix.com", "not-prefix.*", "*"] + - key: "experimental.envoy.filters.a.b[c]" + values: ["exact", "prefix-*", "*-suffix", "*"] + notValues: ["not-exact", "not-prefix-*", "*-not-suffix", "*"] +--- +apiVersion: security.istio.io/v1 +kind: AuthorizationPolicy +metadata: + name: service-account-and-namespace-principal-split +spec: + rules: + - from: + - source: + serviceAccounts: ["baz/sa"] + - source: + principals: ["bar"] + - source: + namespaces: ["bar"] \ No newline at end of file From 6dd0b032de6d87f710c316b198305222b2692556 Mon Sep 17 00:00:00 2001 From: John Howard Date: Wed, 30 Oct 2024 07:20:33 -0700 Subject: [PATCH 3/3] add doc --- security/v1beta1/authorization_policy.pb.go | 2 ++ security/v1beta1/authorization_policy.pb.html | 3 ++- security/v1beta1/authorization_policy.proto | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/security/v1beta1/authorization_policy.pb.go b/security/v1beta1/authorization_policy.pb.go index 5ebe984e9c6..65091861171 100644 --- a/security/v1beta1/authorization_policy.pb.go +++ b/security/v1beta1/authorization_policy.pb.go @@ -647,6 +647,8 @@ type Source struct { // If not set, any service account is allowed. // // No form of wildcard (`*`) is allowed. + // Cannot be set with `principals` or `namespaces`. + // // +protoc-gen-crd:list-value-validation:MaxLength=320 // +kubebuilder:validation:MaxItems=16 ServiceAccounts []string `protobuf:"bytes,11,rep,name=service_accounts,json=serviceAccounts,proto3" json:"service_accounts,omitempty"` diff --git a/security/v1beta1/authorization_policy.pb.html b/security/v1beta1/authorization_policy.pb.html index 96538605376..9343e9c6537 100644 --- a/security/v1beta1/authorization_policy.pb.html +++ b/security/v1beta1/authorization_policy.pb.html @@ -452,7 +452,8 @@

Source

This field requires mTLS enabled and is the same as the source.serviceaccount attribute.

This takes the format <namespace>/<serviceaccount>.

If not set, any service account is allowed.

-

No form of wildcard (*) is allowed.

+

No form of wildcard (*) is allowed. +Cannot be set with principals or namespaces.

diff --git a/security/v1beta1/authorization_policy.proto b/security/v1beta1/authorization_policy.proto index a3325c550ac..37ac5c64a37 100644 --- a/security/v1beta1/authorization_policy.proto +++ b/security/v1beta1/authorization_policy.proto @@ -466,6 +466,8 @@ message Source { // If not set, any service account is allowed. // // No form of wildcard (`*`) is allowed. + // Cannot be set with `principals` or `namespaces`. + // // +protoc-gen-crd:list-value-validation:MaxLength=320 // +kubebuilder:validation:MaxItems=16 repeated string service_accounts = 11;