From e6e6c31289fd77848590108cceeb0798615dd229 Mon Sep 17 00:00:00 2001 From: Caleb Doxsey Date: Tue, 18 Feb 2025 15:20:02 -0700 Subject: [PATCH] add bearer_token_format and idp_access_token_allowed_audiences (#1103) * add bearer_token_format and idp_access_token_allowed_audiences * use main commit * fix bootstrap failing --- apis/ingress/v1/pomerium_types.go | 11 ++++ apis/ingress/v1/zz_generated.deepcopy.go | 14 ++++ .../bases/ingress.pomerium.io_pomerium.yaml | 16 +++++ config/gen_secrets/role.yaml | 1 + deployment.yaml | 17 +++++ go.mod | 2 +- go.sum | 4 +- pomerium/config.go | 23 +++++++ pomerium/ingress_annotations.go | 2 + pomerium/ingress_annotations_test.go | 13 ++-- pomerium/proto.go | 18 ++++++ reference.md | 64 +++++++++++++------ 12 files changed, 158 insertions(+), 27 deletions(-) diff --git a/apis/ingress/v1/pomerium_types.go b/apis/ingress/v1/pomerium_types.go index 41ea622f..055670af 100644 --- a/apis/ingress/v1/pomerium_types.go +++ b/apis/ingress/v1/pomerium_types.go @@ -289,6 +289,17 @@ type PomeriumSpec struct { // +kubebuilder:validation:Optional // +kubebuilder:validation:Enum=auto;http1;http2;http3 CodecType *string `json:"codecType,omitempty"` + + // BearerTokenFormat sets the Bearer Token Format. + // + // +kubebuilder:validation:Optional + // +kubebuilder:validation:Enum=default;idp_access_token;idp_identity_token + BearerTokenFormat *string `json:"bearerTokenFormat,omitempty"` + + // IDPAccessTokenAllowedAudiences specifies the + // idp access token allowed audiences + // list. + IDPAccessTokenAllowedAudiences *[]string `json:"idpAccessTokenAllowedAudiences,omitempty"` } // Timeouts allows to configure global timeouts for all routes. diff --git a/apis/ingress/v1/zz_generated.deepcopy.go b/apis/ingress/v1/zz_generated.deepcopy.go index 828fdaae..2b08f788 100644 --- a/apis/ingress/v1/zz_generated.deepcopy.go +++ b/apis/ingress/v1/zz_generated.deepcopy.go @@ -272,6 +272,20 @@ func (in *PomeriumSpec) DeepCopyInto(out *PomeriumSpec) { *out = new(string) **out = **in } + if in.BearerTokenFormat != nil { + in, out := &in.BearerTokenFormat, &out.BearerTokenFormat + *out = new(string) + **out = **in + } + if in.IDPAccessTokenAllowedAudiences != nil { + in, out := &in.IDPAccessTokenAllowedAudiences, &out.IDPAccessTokenAllowedAudiences + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PomeriumSpec. diff --git a/config/crd/bases/ingress.pomerium.io_pomerium.yaml b/config/crd/bases/ingress.pomerium.io_pomerium.yaml index fb9c6da2..4232b721 100644 --- a/config/crd/bases/ingress.pomerium.io_pomerium.yaml +++ b/config/crd/bases/ingress.pomerium.io_pomerium.yaml @@ -83,6 +83,14 @@ spec: items: type: string type: array + bearerTokenFormat: + description: BearerTokenFormat sets the Bearer + Token Format. + enum: + - default + - idp_access_token + - idp_identity_token + type: string caSecrets: description: CASecret should refer to k8s secrets with key ca.crt containing a CA certificate. @@ -222,6 +230,14 @@ spec: - provider - secret type: object + idpAccessTokenAllowedAudiences: + description: |- + IDPAccessTokenAllowedAudiences specifies the + idp access token allowed audiences + list. + items: + type: string + type: array jwtClaimHeaders: additionalProperties: type: string diff --git a/config/gen_secrets/role.yaml b/config/gen_secrets/role.yaml index a3b5784b..70213663 100644 --- a/config/gen_secrets/role.yaml +++ b/config/gen_secrets/role.yaml @@ -10,3 +10,4 @@ rules: - secrets verbs: - create + - get diff --git a/deployment.yaml b/deployment.yaml index f3d99d22..fc9e5f09 100644 --- a/deployment.yaml +++ b/deployment.yaml @@ -225,6 +225,14 @@ spec: items: type: string type: array + bearerTokenFormat: + description: BearerTokenFormat sets the Bearer + Token Format. + enum: + - default + - idp_access_token + - idp_identity_token + type: string caSecrets: description: CASecret should refer to k8s secrets with key ca.crt containing a CA certificate. @@ -364,6 +372,14 @@ spec: - provider - secret type: object + idpAccessTokenAllowedAudiences: + description: |- + IDPAccessTokenAllowedAudiences specifies the + idp access token allowed audiences + list. + items: + type: string + type: array jwtClaimHeaders: additionalProperties: type: string @@ -655,6 +671,7 @@ rules: - secrets verbs: - create + - get --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/go.mod b/go.mod index 2f9499e2..0aeec933 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/martinlindhe/base36 v1.1.1 github.com/open-policy-agent/opa v1.1.0 github.com/pomerium/csrf v1.7.0 - github.com/pomerium/pomerium v0.28.1-0.20250204182906-81a52db74940 + github.com/pomerium/pomerium v0.28.1-0.20250218200206-b9fd926618e2 github.com/rs/zerolog v1.33.0 github.com/sergi/go-diff v1.3.1 github.com/spf13/cobra v1.8.1 diff --git a/go.sum b/go.sum index 57625db9..4eb9bd02 100644 --- a/go.sum +++ b/go.sum @@ -541,8 +541,8 @@ github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524 h1:3YQY1sb5 github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524/go.mod h1:7fGbUYJnU8RcxZJvUvhukOIBv1G7LWDAHMfDxAf5+Y0= github.com/pomerium/envoy-custom v1.32.4-0.20250114182541-6f6d2147bea6 h1:QLVgpx23jcbgR9qJzIicJ+uXGjQXO0GAy55SCo0Jd9o= github.com/pomerium/envoy-custom v1.32.4-0.20250114182541-6f6d2147bea6/go.mod h1:afbaKE6YfshVUOrYc6XWUWfZcXencWmi1jTc00ki0Oo= -github.com/pomerium/pomerium v0.28.1-0.20250204182906-81a52db74940 h1:Gi6ZFj2KUoI71thjzNKH4y13ip4LPLjABTQN+33P9IY= -github.com/pomerium/pomerium v0.28.1-0.20250204182906-81a52db74940/go.mod h1:8Uf1ya/wSjJyeUo5X4TqctlrYxbc5iPfFG18x1t0Deo= +github.com/pomerium/pomerium v0.28.1-0.20250218200206-b9fd926618e2 h1:UtyGKmmFs/DVuvhOUeFowruCv+xObqAbqNmPqhMZ88o= +github.com/pomerium/pomerium v0.28.1-0.20250218200206-b9fd926618e2/go.mod h1:8Uf1ya/wSjJyeUo5X4TqctlrYxbc5iPfFG18x1t0Deo= github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46 h1:NRTg8JOXCxcIA1lAgD74iYud0rbshbWOB3Ou4+Huil8= github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46/go.mod h1:QqZmx6ZgPxz18va7kqoT4t/0yJtP7YFIDiT/W2n2fZ4= github.com/pomerium/webauthn v0.0.0-20240603205124-0428df511172 h1:TqoPqRgXSHpn+tEJq6H72iCS5pv66j3rPprThUEZg0E= diff --git a/pomerium/config.go b/pomerium/config.go index 96eada04..22aee54f 100644 --- a/pomerium/config.go +++ b/pomerium/config.go @@ -132,6 +132,29 @@ func applySetOtherOptions(_ context.Context, p *pb.Config, c *model.Config) erro } else { p.Settings.PassIdentityHeaders = nil } + if c.Spec.BearerTokenFormat != nil { + switch *c.Spec.BearerTokenFormat { + case "": + p.Settings.BearerTokenFormat = pb.BearerTokenFormat_BEARER_TOKEN_FORMAT_UNKNOWN.Enum() + case "default": + p.Settings.BearerTokenFormat = pb.BearerTokenFormat_BEARER_TOKEN_FORMAT_DEFAULT.Enum() + case "idp_access_token": + p.Settings.BearerTokenFormat = pb.BearerTokenFormat_BEARER_TOKEN_FORMAT_IDP_ACCESS_TOKEN.Enum() + case "idp_identity_token": + p.Settings.BearerTokenFormat = pb.BearerTokenFormat_BEARER_TOKEN_FORMAT_IDP_IDENTITY_TOKEN.Enum() + default: + return fmt.Errorf("unknown bearerTokenFormat %s", *c.Spec.BearerTokenFormat) + } + } else { + p.Settings.BearerTokenFormat = nil + } + if c.Spec.IDPAccessTokenAllowedAudiences != nil { + p.Settings.IdpAccessTokenAllowedAudiences = &pb.Settings_StringList{ + Values: *c.Spec.IDPAccessTokenAllowedAudiences, + } + } else { + p.Settings.IdpAccessTokenAllowedAudiences = nil + } return nil } diff --git a/pomerium/ingress_annotations.go b/pomerium/ingress_annotations.go index ecf87bf2..90812175 100644 --- a/pomerium/ingress_annotations.go +++ b/pomerium/ingress_annotations.go @@ -24,6 +24,7 @@ var ( "allow_public_unauthenticated_access", "allow_spdy", "allow_websockets", + "bearer_token_format", "cors_allow_preflight", "description", "host_path_regex_rewrite_pattern", @@ -31,6 +32,7 @@ var ( "host_rewrite_header", "host_rewrite", "idle_timeout", + "idp_access_token_allowed_audiences", "logo_url", "pass_identity_headers", "prefix_rewrite", diff --git a/pomerium/ingress_annotations_test.go b/pomerium/ingress_annotations_test.go index 11d52313..b1b3a0e4 100644 --- a/pomerium/ingress_annotations_test.go +++ b/pomerium/ingress_annotations_test.go @@ -45,6 +45,7 @@ func TestAnnotations(t *testing.T) { "a/allowed_domains": `["a"]`, "a/allowed_idp_claims": `key: ["val1", "val2"]`, "a/allowed_users": `["a"]`, + "a/bearer_token_format": `idp_access_token`, "a/cors_allow_preflight": "true", "a/description": "DESCRIPTION", "a/health_checks": `[{"timeout": "10s", "interval": "1m", "healthy_threshold": 1, "unhealthy_threshold": 2, "http_health_check": {"path": "/"}}]`, @@ -53,6 +54,7 @@ func TestAnnotations(t *testing.T) { "a/host_rewrite_header": "rewrite-header", "a/host_rewrite": "rewrite", "a/idle_timeout": `60s`, + "a/idp_access_token_allowed_audiences": `["x","y","z"]`, "a/kubernetes_service_account_token_secret": "k8s_token", "a/lb_policy": "LEAST_REQUEST", "a/logo_url": "LOGO_URL", @@ -191,12 +193,15 @@ func TestAnnotations(t *testing.T) { }, SourcePpl: proto.String(`{"allow":{"or":[{"domain":{"is":"pomerium.com"}}]}}`), }}, - TlsSkipVerify: true, - TlsServerName: "my.server.name", - Description: "DESCRIPTION", - LogoUrl: "LOGO_URL", + TlsSkipVerify: true, + TlsServerName: "my.server.name", + Description: "DESCRIPTION", + LogoUrl: "LOGO_URL", + BearerTokenFormat: pb.BearerTokenFormat_BEARER_TOKEN_FORMAT_IDP_ACCESS_TOKEN.Enum(), + IdpAccessTokenAllowedAudiences: &pb.Route_StringList{Values: []string{"x", "y", "z"}}, }, cmpopts.IgnoreUnexported( pb.Route{}, + pb.Route_StringList{}, pb.RouteRewriteHeader{}, pb.Policy{}, structpb.ListValue{}, diff --git a/pomerium/proto.go b/pomerium/proto.go index 433ac43a..0b07f491 100644 --- a/pomerium/proto.go +++ b/pomerium/proto.go @@ -43,6 +43,10 @@ func preprocessAnnotationMessage(md protoreflect.MessageDescriptor, data any) an if v, ok := data.(string); ok { return goDurationStringToProtoJSONDurationString(v) } + case "pomerium.config.Route.StringList": + if v, ok := data.([]any); ok { + return map[string]any{"values": v} + } default: // preprocess all the fields if v, ok := data.(map[string]any); ok { @@ -62,6 +66,20 @@ func preprocessAnnotationMessage(md protoreflect.MessageDescriptor, data any) an } func preprocessAnnotationField(fd protoreflect.FieldDescriptor, data any) any { + if fd.Enum() != nil && fd.Enum().FullName() == "pomerium.config.BearerTokenFormat" { + if v, ok := data.(string); ok { + switch v { + case "": + return "BEARER_TOKEN_FORMAT_UNKNOWN" + case "default": + return "BEARER_TOKEN_FORMAT_DEFAULT" + case "idp_access_token": + return "BEARER_TOKEN_FORMAT_IDP_ACCESS_TOKEN" + case "idp_identity_token": + return "BEARER_TOKEN_FORMAT_IDP_IDENTITY_TOKEN" + } + } + } // if this is a repeated field, handle each of the field values separately if fd.IsList() { vs, ok := data.([]any) diff --git a/reference.md b/reference.md index b79416d2..292156f7 100644 --- a/reference.md +++ b/reference.md @@ -8,6 +8,7 @@ Pomerium-specific parameters should be configured via the `ingress.pomerium.io/P The default Pomerium deployment is listening to the CRD `global`, that may be customized via command line parameters. Pomerium posts updates to the CRD `/status`: + ```shell kubectl describe pomerium ``` @@ -72,6 +73,22 @@ PomeriumSpec defines Pomerium-specific configuration parameters. + + +

+ bearerTokenFormat   + + string  + +

+

+ + BearerTokenFormat sets the Bearer Token Format. +

+ + + +

@@ -157,6 +174,22 @@ PomeriumSpec defines Pomerium-specific configuration parameters. + + +

+ idpAccessTokenAllowedAudiences   + + []string  + +

+

+ + IDPAccessTokenAllowedAudiences specifies the idp access token allowed audiences list. +

+ + + +

@@ -307,9 +340,8 @@ PomeriumSpec defines Pomerium-specific configuration parameters. - - + ### `authenticate` @@ -356,9 +388,8 @@ Authenticate sets authenticate service parameters. If not specified, a Pomerium- - - + ### `cookie` @@ -453,9 +484,8 @@ Cookie defines Pomerium session cookie options. - - + ### `identityProvider` @@ -605,9 +635,8 @@ IdentityProvider configure single-sign-on authentication and user identity detai - - + ### `postgres` @@ -676,9 +705,8 @@ Postgres specifies PostgreSQL database connection parameters - - + ### `refreshDirectory` @@ -728,9 +756,8 @@ RefreshDirectory is no longer supported, please see - - + ### `timeouts` @@ -830,9 +856,8 @@ Timeout specifies the