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.
+ |
+
+
+ |
+
+ 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.
+
+ |
+
+
+ |
+
+ 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 `/`.
//
|