From b19be1bf16778b796d74ba8cb1001a8c4c813b01 Mon Sep 17 00:00:00 2001 From: Anders Ingemann Date: Wed, 19 Jul 2023 14:17:57 +0200 Subject: [PATCH] Implement client-side mTLS support settings --- apis/ingress/v1/pomerium_types.go | 5 +++++ apis/ingress/v1/zz_generated.deepcopy.go | 5 +++++ .../bases/ingress.pomerium.io_pomerium.yaml | 7 +++++++ controllers/settings/fetch.go | 10 +++++++++ model/ingress_config.go | 4 ++++ pomerium/config.go | 21 +++++++++++++++++++ reference.md | 16 ++++++++++++++ 7 files changed, 68 insertions(+) diff --git a/apis/ingress/v1/pomerium_types.go b/apis/ingress/v1/pomerium_types.go index 25baa711..710c3259 100644 --- a/apis/ingress/v1/pomerium_types.go +++ b/apis/ingress/v1/pomerium_types.go @@ -243,6 +243,11 @@ type PomeriumSpec struct { // +optional CASecrets []string `json:"caSecrets"` + // ClientCASecret is a list of secrets of type Opaque to use for client-side mTLS. + // Specify the corresponding CRL with the ca.crl key + // +optional + ClientCASecrets []string `json:"clientCASecrets"` + // Secrets references a Secret with Pomerium bootstrap parameters. // //

diff --git a/apis/ingress/v1/zz_generated.deepcopy.go b/apis/ingress/v1/zz_generated.deepcopy.go index 7614522c..bb715f86 100644 --- a/apis/ingress/v1/zz_generated.deepcopy.go +++ b/apis/ingress/v1/zz_generated.deepcopy.go @@ -204,6 +204,11 @@ func (in *PomeriumSpec) DeepCopyInto(out *PomeriumSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.ClientCASecrets != nil { + in, out := &in.ClientCASecrets, &out.ClientCASecrets + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.Storage != nil { in, out := &in.Storage, &out.Storage *out = new(Storage) diff --git a/config/crd/bases/ingress.pomerium.io_pomerium.yaml b/config/crd/bases/ingress.pomerium.io_pomerium.yaml index 03d5cf94..9174916d 100644 --- a/config/crd/bases/ingress.pomerium.io_pomerium.yaml +++ b/config/crd/bases/ingress.pomerium.io_pomerium.yaml @@ -76,6 +76,13 @@ spec: items: type: string type: array + clientCASecrets: + description: Client CAs is a list of secrets of type Opaque to use + for client-side mTLS. Specify the corresponding CRL with the ca.crl + key + items: + type: string + type: array cookie: description: Cookie defines Pomerium session cookie options. properties: diff --git a/controllers/settings/fetch.go b/controllers/settings/fetch.go index d88ef0b3..a933a449 100644 --- a/controllers/settings/fetch.go +++ b/controllers/settings/fetch.go @@ -111,6 +111,16 @@ func fetchConfigSecrets(ctx context.Context, client client.Client, cfg *model.Co } return nil }, + func() error { + for _, clientCASecret := range s.ClientCASecrets { + secret, err := get(clientCASecret)() + if err != nil { + return fmt.Errorf("ca: %w", err) + } + cfg.ClientCASecrets = append(cfg.ClientCASecrets, secret) + } + return nil + }, func() error { if s.IdentityProvider == nil { return nil diff --git a/model/ingress_config.go b/model/ingress_config.go index dbacfe4a..e282fc99 100644 --- a/model/ingress_config.go +++ b/model/ingress_config.go @@ -45,6 +45,8 @@ const ( StorageConnectionStringKey = "connection" // CAKey is certificate authority secret key CAKey = "ca.crt" + // CAKey is certificate authority CRL + CRLKey = "ca.crl" ) // StorageSecrets is a convenience grouping of storage-related secrets @@ -84,6 +86,8 @@ type Config struct { CASecrets []*corev1.Secret // Certs are fetched certs from settings.Certificates Certs map[types.NamespacedName]*corev1.Secret + // ClientCASecrets are fetched certs and crls from settings.ClientCASecrets + ClientCASecrets []*corev1.Secret // RequestParams is a secret from Settings.IdentityProvider.RequestParams RequestParams *corev1.Secret // IdpSecret is Settings.IdentityProvider.Secret diff --git a/pomerium/config.go b/pomerium/config.go index 3f8991c8..0475c63e 100644 --- a/pomerium/config.go +++ b/pomerium/config.go @@ -34,6 +34,7 @@ func applyConfig(ctx context.Context, p *pb.Config, c *model.Config) error { opts := []applyOpt{ {"ca", applyCertificateAuthority}, + {"client ca", applyClientCertificate}, {"certs", applyCerts}, {"authenticate", applyAuthenticate}, {"cookie", applyCookie}, @@ -132,6 +133,26 @@ func applyCertificateAuthority(_ context.Context, p *pb.Config, c *model.Config) return nil } +func applyClientCertificate(_ context.Context, p *pb.Config, c *model.Config) error { + if len(c.ClientCASecrets) == 0 { + return nil + } + + var crtBuf bytes.Buffer + var crlBuf bytes.Buffer + + for _, secret := range c.ClientCASecrets { + crtBuf.Write(secret.Data[model.CAKey]) + crtBuf.WriteRune('\n') + crlBuf.Write(secret.Data[model.CRLKey]) + crlBuf.WriteRune('\n') + } + + p.Settings.ClientCa = proto.String(base64.StdEncoding.EncodeToString(crtBuf.Bytes())) + p.Settings.ClientCrl = proto.String(base64.StdEncoding.EncodeToString(crlBuf.Bytes())) + return nil +} + func applyCerts(_ context.Context, p *pb.Config, c *model.Config) error { if len(c.Certs) != len(c.Spec.Certificates) { return fmt.Errorf("expected %d cert secrets, only %d was fetched. this is a bug", len(c.Spec.Certificates), len(c.Certs)) diff --git a/reference.md b/reference.md index f3a157ac..447f70a5 100644 --- a/reference.md +++ b/reference.md @@ -75,6 +75,22 @@ PomeriumSpec defines Pomerium-specific configuration parameters. + + +

+ clientCASecrets   + + []string  + +

+

+ + Client CAs is a list of secrets of type TLS to use for client-side mTLS. Specify the corresponding CRL with the ca.crl key +

+ + + +