From 2b8503744c575bc02cb9d9c2dea5f451b7fc79b6 Mon Sep 17 00:00:00 2001 From: John Howard Date: Fri, 18 Oct 2024 13:20:25 -0700 Subject: [PATCH 1/4] 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 | 22 +++++ security/v1beta1/authorization_policy.proto | 13 +++ 4 files changed, 120 insertions(+), 34 deletions(-) diff --git a/kubernetes/customresourcedefinitions.gen.yaml b/kubernetes/customresourcedefinitions.gen.yaml index 5360fe804dd..d4cfa1506d0 100644 --- a/kubernetes/customresourcedefinitions.gen.yaml +++ b/kubernetes/customresourcedefinitions.gen.yaml @@ -14717,6 +14717,11 @@ spec: items: type: string type: array + notServiceAccounts: + description: Optional. + items: + type: string + type: array principals: description: Optional. items: @@ -14732,6 +14737,11 @@ spec: items: type: string type: array + serviceAccounts: + description: Optional. + items: + type: string + type: array type: object type: object type: array @@ -15077,6 +15087,11 @@ spec: items: type: string type: array + notServiceAccounts: + description: Optional. + items: + type: string + type: array principals: description: Optional. items: @@ -15092,6 +15107,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 f4d8ba3e163..6f02256c40b 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 0613ae5dd71..009795fb209 100644 --- a/security/v1beta1/authorization_policy.pb.html +++ b/security/v1beta1/authorization_policy.pb.html @@ -495,6 +495,7 @@

Source

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.

@@ -547,6 +548,27 @@

Source

A list of negative match of namespaces.

+ + + +
+
string[]
+
+ +

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.

+ + + + +
+
string[]
+
+ +

A list of negative match of service accounts.

+ 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 5b790253e9c9d66f2ad8f09f1e9e6579fd105634 Mon Sep 17 00:00:00 2001 From: John Howard Date: Mon, 28 Oct 2024 13:31:59 -0700 Subject: [PATCH 2/4] Tests and validation --- kubernetes/customresourcedefinitions.gen.yaml | 24 +++++ 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, 165 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 d4cfa1506d0..fe8bc7d21e1 100644 --- a/kubernetes/customresourcedefinitions.gen.yaml +++ b/kubernetes/customresourcedefinitions.gen.yaml @@ -14720,7 +14720,9 @@ spec: notServiceAccounts: description: Optional. items: + maxLength: 320 type: string + maxItems: 16 type: array principals: description: Optional. @@ -14740,10 +14742,19 @@ 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. @@ -14817,6 +14828,7 @@ spec: type: object type: array type: object + maxItems: 512 type: array selector: description: Optional. @@ -15090,7 +15102,9 @@ spec: notServiceAccounts: description: Optional. items: + maxLength: 320 type: string + maxItems: 16 type: array principals: description: Optional. @@ -15110,10 +15124,19 @@ 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. @@ -15187,6 +15210,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 6f02256c40b..ef566b3e440 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 009795fb209..29a81eb799b 100644 --- a/security/v1beta1/authorization_policy.pb.html +++ b/security/v1beta1/authorization_policy.pb.html @@ -559,6 +559,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.

@@ -568,6 +569,8 @@

Source

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 b55e0db556d681110258b7ee251af949d594ce8a Mon Sep 17 00:00:00 2001 From: John Howard Date: Wed, 30 Oct 2024 07:20:33 -0700 Subject: [PATCH 3/4] 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 ef566b3e440..326722d8188 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 29a81eb799b..722449695ae 100644 --- a/security/v1beta1/authorization_policy.pb.html +++ b/security/v1beta1/authorization_policy.pb.html @@ -559,7 +559,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; From 2390eddad5ddd6e7fccb39ee3c3aeff7ee2a61dc Mon Sep 17 00:00:00 2001 From: John Howard Date: Wed, 18 Dec 2024 13:52:27 -0800 Subject: [PATCH 4/4] Clarify comment that this is a KSA --- security/v1beta1/authorization_policy.pb.go | 4 ++-- security/v1beta1/authorization_policy.pb.html | 4 ++-- security/v1beta1/authorization_policy.proto | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/security/v1beta1/authorization_policy.pb.go b/security/v1beta1/authorization_policy.pb.go index 326722d8188..7173c90f96b 100644 --- a/security/v1beta1/authorization_policy.pb.go +++ b/security/v1beta1/authorization_policy.pb.go @@ -639,7 +639,7 @@ 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. + // Optional. A list of Kubernetes 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 `/`. @@ -652,7 +652,7 @@ type Source struct { // +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. + // Optional. A list of negative match of Kubernetes service accounts. // // This takes the format `/`. // diff --git a/security/v1beta1/authorization_policy.pb.html b/security/v1beta1/authorization_policy.pb.html index 722449695ae..8b9d9df943f 100644 --- a/security/v1beta1/authorization_policy.pb.html +++ b/security/v1beta1/authorization_policy.pb.html @@ -555,7 +555,7 @@

Source

string[]
-

A list of service accounts derived from the peer certificate. +

A list of Kubernetes 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.

@@ -569,7 +569,7 @@

Source

string[]
-

A list of negative match of service accounts.

+

A list of negative match of Kubernetes 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 37ac5c64a37..5ce49165fb2 100644 --- a/security/v1beta1/authorization_policy.proto +++ b/security/v1beta1/authorization_policy.proto @@ -458,7 +458,7 @@ 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. + // Optional. A list of Kubernetes 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 `/`. @@ -472,7 +472,7 @@ message Source { // +kubebuilder:validation:MaxItems=16 repeated string service_accounts = 11; - // Optional. A list of negative match of service accounts. + // Optional. A list of negative match of Kubernetes service accounts. // // This takes the format `/`. //