Merge branch 'wasaga/zero-retry' into wasaga/zero-bootstrap-config

This commit is contained in:
Denis Mishin 2023-08-12 23:10:29 -04:00
commit 47b0f7985e
41 changed files with 2963 additions and 698 deletions

View file

@ -94,12 +94,12 @@ func newPolicyEvaluator(opts *config.Options, store *store.Store) (*evaluator.Ev
ctx, span := trace.StartSpan(ctx, "authorize.newPolicyEvaluator")
defer span.End()
clientCA, err := opts.GetClientCA()
clientCA, err := opts.DownstreamMTLS.GetCA()
if err != nil {
return nil, fmt.Errorf("authorize: invalid client CA: %w", err)
}
clientCRL, err := opts.GetClientCRL()
clientCRL, err := opts.DownstreamMTLS.GetCRL()
if err != nil {
return nil, fmt.Errorf("authorize: invalid client CRL: %w", err)
}
@ -114,10 +114,24 @@ func newPolicyEvaluator(opts *config.Options, store *store.Store) (*evaluator.Ev
return nil, fmt.Errorf("authorize: invalid signing key: %w", err)
}
// It is important to add an invalid_client_certificate rule even when the
// mTLS enforcement behavior is set to reject connections at the listener
// level, because of the per-route TLSDownstreamClientCA setting.
addDefaultClientCertificateRule :=
opts.DownstreamMTLS.GetEnforcement() != config.MTLSEnforcementPolicy
clientCertConstraints, err := evaluator.ClientCertConstraintsFromConfig(&opts.DownstreamMTLS)
if err != nil {
return nil, fmt.Errorf(
"authorize: internal error: couldn't build client cert constraints: %w", err)
}
return evaluator.New(ctx, store,
evaluator.WithPolicies(opts.GetAllPolicies()),
evaluator.WithClientCA(clientCA),
evaluator.WithAddDefaultClientCertificateRule(addDefaultClientCertificateRule),
evaluator.WithClientCRL(clientCRL),
evaluator.WithClientCertConstraints(clientCertConstraints),
evaluator.WithSigningKey(signingKey),
evaluator.WithAuthenticateURL(authenticateURL.String()),
evaluator.WithGoogleCloudServerlessAuthenticationServiceAccount(opts.GetGoogleCloudServerlessAuthenticationServiceAccount()),

View file

@ -8,6 +8,8 @@ type evaluatorConfig struct {
policies []config.Policy
clientCA []byte
clientCRL []byte
addDefaultClientCertificateRule bool
clientCertConstraints ClientCertConstraints
signingKey []byte
authenticateURL string
googleCloudServerlessAuthenticationServiceAccount string
@ -46,6 +48,21 @@ func WithClientCRL(clientCRL []byte) Option {
}
}
// WithAddDefaultClientCertificateRule sets whether to add a default
// invalid_client_certificate deny rule to all policies.
func WithAddDefaultClientCertificateRule(addDefaultClientCertificateRule bool) Option {
return func(cfg *evaluatorConfig) {
cfg.addDefaultClientCertificateRule = addDefaultClientCertificateRule
}
}
// WithClientCertConstraints sets addition client certificate constraints.
func WithClientCertConstraints(constraints *ClientCertConstraints) Option {
return func(cfg *evaluatorConfig) {
cfg.clientCertConstraints = *constraints
}
}
// WithSigningKey sets the signing key and algorithm in the config.
func WithSigningKey(signingKey []byte) Option {
return func(cfg *evaluatorConfig) {

View file

@ -89,11 +89,12 @@ type Result struct {
// An Evaluator evaluates policies.
type Evaluator struct {
store *store.Store
policyEvaluators map[uint64]*PolicyEvaluator
headersEvaluators *HeadersEvaluator
clientCA []byte
clientCRL []byte
store *store.Store
policyEvaluators map[uint64]*PolicyEvaluator
headersEvaluators *HeadersEvaluator
clientCA []byte
clientCRL []byte
clientCertConstraints ClientCertConstraints
}
// New creates a new Evaluator.
@ -114,6 +115,7 @@ func New(ctx context.Context, store *store.Store, options ...Option) (*Evaluator
e.clientCA = cfg.clientCA
e.clientCRL = cfg.clientCRL
e.clientCertConstraints = cfg.clientCertConstraints
e.policyEvaluators = make(map[uint64]*PolicyEvaluator)
for i := range cfg.policies {
@ -122,8 +124,8 @@ func New(ctx context.Context, store *store.Store, options ...Option) (*Evaluator
if err != nil {
return nil, fmt.Errorf("authorize: error computing policy route id: %w", err)
}
clientCA, _ := e.getClientCA(&configPolicy)
policyEvaluator, err := NewPolicyEvaluator(ctx, store, &configPolicy, clientCA)
policyEvaluator, err :=
NewPolicyEvaluator(ctx, store, &configPolicy, cfg.addDefaultClientCertificateRule)
if err != nil {
return nil, err
}
@ -211,8 +213,8 @@ func (e *Evaluator) evaluatePolicy(ctx context.Context, req *Request) (*PolicyRe
return nil, err
}
isValidClientCertificate, err :=
isValidClientCertificate(clientCA, string(e.clientCRL), req.HTTP.ClientCertificate)
isValidClientCertificate, err := isValidClientCertificate(
clientCA, string(e.clientCRL), req.HTTP.ClientCertificate, e.clientCertConstraints)
if err != nil {
return nil, fmt.Errorf("authorize: error validating client certificate: %w", err)
}
@ -225,7 +227,7 @@ func (e *Evaluator) evaluatePolicy(ctx context.Context, req *Request) (*PolicyRe
}
func (e *Evaluator) evaluateHeaders(ctx context.Context, req *Request) (*HeadersResponse, error) {
headersReq := NewHeadersRequestFromPolicy(req.Policy, req.HTTP.Hostname)
headersReq := NewHeadersRequestFromPolicy(req.Policy, req.HTTP)
headersReq.Session = req.Session
res, err := e.headersEvaluators.Evaluate(ctx, headersReq)
if err != nil {

View file

@ -115,6 +115,18 @@ func TestEvaluator(t *testing.T) {
AllowedUsers: []string{"a@example.com"},
TLSDownstreamClientCA: base64.StdEncoding.EncodeToString([]byte(testCA)),
},
{
To: config.WeightedURLs{{URL: *mustParseURL("https://to12.example.com")}},
AllowedUsers: []string{"a@example.com"},
Policy: &config.PPLPolicy{
Policy: &parser.Policy{
Rules: []parser.Rule{{
Action: parser.ActionDeny,
Or: []parser.Criterion{{Name: "invalid_client_certificate"}},
}},
},
},
},
}
options := []Option{
WithAuthenticateURL("https://authn.example.com"),
@ -129,7 +141,8 @@ func TestEvaluator(t *testing.T) {
t.Run("client certificate (default CA)", func(t *testing.T) {
// Clone the existing options and add a default client CA.
options := append([]Option(nil), options...)
options = append(options, WithClientCA([]byte(testCA)))
options = append(options, WithClientCA([]byte(testCA)),
WithAddDefaultClientCertificateRule(true))
t.Run("missing", func(t *testing.T) {
res, err := eval(t, options, nil, &Request{
Policy: &policies[0],
@ -159,6 +172,9 @@ func TestEvaluator(t *testing.T) {
})
})
t.Run("client certificate (per-policy CA)", func(t *testing.T) {
// Clone existing options and add the default client certificate rule.
options := append([]Option(nil), options...)
options = append(options, WithAddDefaultClientCertificateRule(true))
t.Run("missing", func(t *testing.T) {
res, err := eval(t, options, nil, &Request{
Policy: &policies[10],
@ -190,6 +206,38 @@ func TestEvaluator(t *testing.T) {
assert.False(t, res.Deny.Value)
})
})
t.Run("explicit client certificate rule", func(t *testing.T) {
// Clone the existing options and add a default client CA (but no
// default deny rule).
options := append([]Option(nil), options...)
options = append(options, WithClientCA([]byte(testCA)))
t.Run("invalid but allowed", func(t *testing.T) {
res, err := eval(t, options, nil, &Request{
Policy: &policies[0], // no explicit deny rule
HTTP: RequestHTTP{
ClientCertificate: ClientCertificateInfo{
Presented: true,
Leaf: testUntrustedCert,
},
},
})
require.NoError(t, err)
assert.False(t, res.Deny.Value)
})
t.Run("invalid", func(t *testing.T) {
res, err := eval(t, options, nil, &Request{
Policy: &policies[11], // policy has explicit deny rule
HTTP: RequestHTTP{
ClientCertificate: ClientCertificateInfo{
Presented: true,
Leaf: testUntrustedCert,
},
},
})
require.NoError(t, err)
assert.Equal(t, NewRuleResult(true, criteria.ReasonInvalidClientCertificate), res.Deny)
})
})
t.Run("identity_headers", func(t *testing.T) {
t.Run("kubernetes", func(t *testing.T) {
res, err := eval(t, options, []proto.Message{

View file

@ -3,52 +3,120 @@ package evaluator
import (
"context"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"regexp"
"strings"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/pkg/cryptutil"
)
var isValidClientCertificateCache, _ = lru.New2Q[[3]string, bool](100)
// ClientCertConstraints contains additional constraints to validate when
// verifying a client certificate.
type ClientCertConstraints struct {
// MaxVerifyDepth is the maximum allowed certificate chain depth (not
// counting the leaf certificate). A value of 0 indicates no maximum.
MaxVerifyDepth uint32
func isValidClientCertificate(ca, crl string, certInfo ClientCertificateInfo) (bool, error) {
// SANMatchers is a map of SAN type to regex match expression. When
// non-empty, a client certificate must contain at least one Subject
// Alternative Name that matches one of the expessions.
SANMatchers SANMatchers
}
// SANMatchers is a map of SAN type to regex match expression.
type SANMatchers = map[config.SANType]*regexp.Regexp
// ClientCertConstraintsFromConfig populates a new ClientCertConstraints struct
// based on the provided configuration.
func ClientCertConstraintsFromConfig(
cfg *config.DownstreamMTLSSettings,
) (*ClientCertConstraints, error) {
constraints := &ClientCertConstraints{
MaxVerifyDepth: cfg.GetMaxVerifyDepth(),
}
// Combine all SAN match patterns for a given type into one expression.
patternsByType := make(map[config.SANType][]string)
for i := range cfg.MatchSubjectAltNames {
m := &cfg.MatchSubjectAltNames[i]
patternsByType[m.Type] = append(patternsByType[m.Type], m.Pattern)
}
matchers := make(SANMatchers)
for k, v := range patternsByType {
var s strings.Builder
s.WriteString("^(")
s.WriteString(v[0])
for _, p := range v[1:] {
s.WriteString(")|(")
s.WriteString(p)
}
s.WriteString(")$")
r, err := regexp.Compile(s.String())
if err != nil {
return nil, err
}
matchers[k] = r
}
if len(matchers) > 0 {
constraints.SANMatchers = matchers
}
return constraints, nil
}
var isValidClientCertificateCache, _ = lru.New2Q[[5]string, bool](100)
func isValidClientCertificate(
ca, crl string, certInfo ClientCertificateInfo, constraints ClientCertConstraints,
) (bool, error) {
// when ca is the empty string, client certificates are not required
if ca == "" {
return true, nil
}
cert := certInfo.Leaf
intermediates := certInfo.Intermediates
if cert == "" {
return false, nil
}
cacheKey := [3]string{ca, crl, cert}
constraintsJSON, err := json.Marshal(constraints)
if err != nil {
return false, fmt.Errorf("internal error: failed to serialize constraints: %w", err)
}
cacheKey := [5]string{ca, crl, cert, intermediates, string(constraintsJSON)}
value, ok := isValidClientCertificateCache.Get(cacheKey)
if ok {
return value, nil
}
roots, err := parseCertificates([]byte(ca))
if err != nil {
return false, err
}
roots := x509.NewCertPool()
roots.AppendCertsFromPEM([]byte(ca))
intermediatesPool := x509.NewCertPool()
intermediatesPool.AppendCertsFromPEM([]byte(intermediates))
xcert, err := parseCertificate(cert)
if err != nil {
return false, err
}
crls, err := parseCRLs([]byte(crl))
crls, err := cryptutil.ParseCRLs([]byte(crl))
if err != nil {
return false, err
}
verifyErr := verifyClientCertificate(xcert, roots, crls)
verifyErr := verifyClientCertificate(xcert, roots, intermediatesPool, crls, constraints)
valid := verifyErr == nil
if verifyErr != nil {
@ -60,55 +128,133 @@ func isValidClientCertificate(ca, crl string, certInfo ClientCertificateInfo) (b
return valid, nil
}
var errCertificateRevoked = errors.New("certificate revoked")
func verifyClientCertificate(
cert *x509.Certificate,
roots map[string]*x509.Certificate,
roots *x509.CertPool,
intermediates *x509.CertPool,
crls map[string]*x509.RevocationList,
constraints ClientCertConstraints,
) error {
rootPool := x509.NewCertPool()
for _, root := range roots {
rootPool.AddCert(root)
}
if _, err := cert.Verify(x509.VerifyOptions{
Roots: rootPool,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}); err != nil {
chains, err := cert.Verify(x509.VerifyOptions{
Roots: roots,
Intermediates: intermediates,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
})
if err != nil {
return err
}
// Consult any CRL for the presented certificate's Issuer.
issuer := string(cert.RawIssuer)
crl := crls[issuer]
if crl == nil {
return nil
}
// Do we have a corresponding trusted CA certificate?
root, ok := roots[issuer]
if !ok {
return fmt.Errorf("could not check CRL: no matching trusted CA for issuer %s",
cert.Issuer)
}
// Is the CRL signature itself valid?
if err := crl.CheckSignatureFrom(root); err != nil {
return fmt.Errorf("could not check CRL for issuer %s: signature verification "+
"error: %w", cert.Issuer, err)
}
// Is the client certificate listed as revoked in this CRL?
for i := range crl.RevokedCertificates {
if cert.SerialNumber.Cmp(crl.RevokedCertificates[i].SerialNumber) == 0 {
return errCertificateRevoked
// At least one of the verified chains must also pass revocation checking
// and satisfy any additional constraints.
err = errors.New("internal error: no verified chains")
for _, chain := range chains {
err = validateClientCertificateChain(chain, crls, constraints)
if err == nil {
return nil
}
}
// Return an error from one of the chains that did not validate.
// (In the common case there will be at most one verified chain.)
return err
}
func validateClientCertificateChain(
chain []*x509.Certificate,
crls map[string]*x509.RevocationList,
constraints ClientCertConstraints,
) error {
if constraints.MaxVerifyDepth > 0 {
if d := uint32(len(chain) - 1); d > constraints.MaxVerifyDepth {
return fmt.Errorf("chain depth %d exceeds max_verify_depth %d",
d, constraints.MaxVerifyDepth)
}
}
if err := validateClientCertificateSANs(chain, constraints.SANMatchers); err != nil {
return err
}
// Consult CRLs for all CAs in the chain (that is, all certificates except
// for the first one). To match Envoy's behavior, if a CRL is provided for
// any CA in the chain, CRLs must be provided for all CAs in the chain (see
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto).
var anyIssuerHasCRL bool
var lastIssuerWithoutCRL *x509.Certificate
for i := 0; i < len(chain)-1; i++ {
cert, issuer := chain[i], chain[i+1]
crl := crls[string(issuer.RawSubject)]
if crl == nil {
lastIssuerWithoutCRL = issuer
continue
}
anyIssuerHasCRL = true
// Is the CRL signature itself valid?
if err := crl.CheckSignatureFrom(issuer); err != nil {
return fmt.Errorf("CRL signature verification failed for issuer %q: %w",
issuer.Subject, err)
}
// Is the certificate listed as revoked in the CRL?
for i := range crl.RevokedCertificates {
if cert.SerialNumber.Cmp(crl.RevokedCertificates[i].SerialNumber) == 0 {
return fmt.Errorf("certificate %q was revoked", cert.Subject)
}
}
}
if anyIssuerHasCRL && lastIssuerWithoutCRL != nil {
return fmt.Errorf("no CRL provided for issuer %q", lastIssuerWithoutCRL.Subject)
}
return nil
}
var errNoSANMatch = errors.New("no matching Subject Alternative Name")
func validateClientCertificateSANs(chain []*x509.Certificate, matchers SANMatchers) error {
if len(matchers) == 0 {
return nil
} else if len(chain) == 0 {
return errors.New("internal error: no certificates in verified chain")
}
cert := chain[0]
if r := matchers[config.SANTypeDNS]; r != nil {
for _, name := range cert.DNSNames {
if r.MatchString(name) {
return nil
}
}
}
if r := matchers[config.SANTypeEmail]; r != nil {
for _, email := range cert.EmailAddresses {
if r.MatchString(email) {
return nil
}
}
}
if r := matchers[config.SANTypeIPAddress]; r != nil {
for _, ip := range cert.IPAddresses {
if r.MatchString(ip.String()) {
return nil
}
}
}
if r := matchers[config.SANTypeURI]; r != nil {
for _, uri := range cert.URIs {
if r.MatchString(uri.String()) {
return nil
}
}
}
return errNoSANMatch
}
func parseCertificate(pemStr string) (*x509.Certificate, error) {
block, _ := pem.Decode([]byte(pemStr))
if block == nil {
@ -119,41 +265,3 @@ func parseCertificate(pemStr string) (*x509.Certificate, error) {
}
return x509.ParseCertificate(block.Bytes)
}
func parseCertificates(certs []byte) (map[string]*x509.Certificate, error) {
m := make(map[string]*x509.Certificate)
for {
var block *pem.Block
block, certs = pem.Decode(certs)
if block == nil {
return m, nil
}
if block.Type != "CERTIFICATE" {
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}
m[string(cert.RawSubject)] = cert
}
}
func parseCRLs(crl []byte) (map[string]*x509.RevocationList, error) {
m := make(map[string]*x509.RevocationList)
for {
var block *pem.Block
block, crl = pem.Decode(crl)
if block == nil {
return m, nil
}
if block.Type != "X509 CRL" {
continue
}
l, err := x509.ParseRevocationList(block.Bytes)
if err != nil {
return nil, err
}
m[string(l.RawIssuer)] = l
}
}

View file

@ -1,9 +1,13 @@
package evaluator
import (
"regexp"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pomerium/pomerium/config"
)
// These certificates can be regenerated by running:
@ -14,71 +18,150 @@ import (
const (
testCA = `
-----BEGIN CERTIFICATE-----
MIIBZzCCAQ6gAwIBAgICEAAwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwNzMxMTUzMzE5WjAaMRgw
MIIBaDCCAQ6gAwIBAgICEAAwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAaMRgw
FgYDVQQDEw9UcnVzdGVkIFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AARGMVCBvgbkVB3OPltnBHAy9s9rtog2rlnzZ4BKzPBbLEM0uPYTOZa0LLxSMtCj
N+Bu3wfGPgHU6/pJ2uEky7/Uo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
BAUwAwEB/zAdBgNVHQ4EFgQUXep6D8FTP6+5ZdR/HjP3pYfmxkwwCgYIKoZIzj0E
AwIDRwAwRAIgSS5J6ii/n0gf2/UAMFb+UVG8n0nb1dcBCG55fSlWlVECIENVK+X3
6SfUhfYSVBvOdS08AzMVvOM7aZbWaY9UirIf
AAR2/RkzmSK6paoeTKFx1Bd52ZCg29ulJlMxFdSZT8FlmmaK9mN6KWwO+NHYObiW
y3AQuoSTrZXlrlRW5ANvMI+io0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
BAUwAwEB/zAdBgNVHQ4EFgQUJGFVU2UOvOVgaY9YcCUiunGpiCQwCgYIKoZIzj0E
AwIDSAAwRQIhAMU5/NjpitOSbUobtjeOriPH8JRo9qy1iFyeVNAcdVvgAiAewq2A
PhgzWTw5F9PJg++9i+xGQTqHs3ZirG27cCjvhQ==
-----END CERTIFICATE-----
`
testValidCert = `
-----BEGIN CERTIFICATE-----
MIIBYTCCAQigAwIBAgICEAEwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwNzMxMTUzMzE5WjAeMRww
MIIBYjCCAQigAwIBAgICEAEwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAeMRww
GgYDVQQDExN0cnVzdGVkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEfAYP3ZwiKJgk9zXpR/CMHYlAxjweJaMJihIS2FTA5gb0xBcTEe5AGpNF
CHWPk4YCB25VeHg9GmY9Q1+qDD1hdqM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
HwYDVR0jBBgwFoAUXep6D8FTP6+5ZdR/HjP3pYfmxkwwCgYIKoZIzj0EAwIDRwAw
RAIgProROtxpvKS/qjrjonSvacnhdU0JwoXj2DgYvF/qjrUCIAXlHkdEzyXmTLuu
/YxuOibV35vlaIzj21GRj4pYmVR1
AQcDQgAEcWa1Bz6mpsLnM1VD8gtzELjzjEp9Dopp/xWScFO9qtay5SBOeX+Ftr0O
8+/RkoKHzGgZ80gr6xQyUJL3MCwVZKM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
HwYDVR0jBBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwCgYIKoZIzj0EAwIDSAAw
RQIgXM1ogmy0vcz4lYzji5X3In1n2GLOFNTgucFPkM0GtqgCIQCsXPs/0OjSFyDR
FBqAm1NqDJcxq685fS9t3VfHwapcVA==
-----END CERTIFICATE-----
`
testUntrustedCert = `
-----BEGIN CERTIFICATE-----
MIIBZzCCAQygAwIBAgICEAEwCgYIKoZIzj0EAwIwHDEaMBgGA1UEAxMRVW50cnVz
dGVkIFJvb3QgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zMzA3MzExNTMzMTlaMCAx
MIIBZjCCAQygAwIBAgICEAEwCgYIKoZIzj0EAwIwHDEaMBgGA1UEAxMRVW50cnVz
dGVkIFJvb3QgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zMzA4MDcxODAzMjFaMCAx
HjAcBgNVBAMTFXVudHJ1c3RlZCBjbGllbnQgY2VydDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABBG2Qo/l0evcNKjwaJsi04BJJh7ec064lRiKaRMNRUK+UxkKmfbn
0FobVtlioTmzeWCX8OJFPfO7y7/VLMiGVr+jODA2MBMGA1UdJQQMMAoGCCsGAQUF
BwMCMB8GA1UdIwQYMBaAFCd2l26OflZF3LTFUEBB54ZQV3AUMAoGCCqGSM49BAMC
A0kAMEYCIQCYEk3D4nHevIlKFg6f7O2/GdptzKU6F05pz4B3Aa8ahAIhAJcBGUNm
cqQQJNOelJJmMeFOzmmTk7oNFxCGEC00wlGn
SM49AwEHA0IABJxEIKqLhhMEm5XZXkT+p+hlC2TFyaW0HIZqoE9navJrAcUB8L2M
mVQ+/wLaCznJHLeSLn46uGH5p1hoGFqOrdajODA2MBMGA1UdJQQMMAoGCCsGAQUF
BwMCMB8GA1UdIwQYMBaAFIp2rlIiSnr33ea3cGyLsX4LEYwWMAoGCCqGSM49BAMC
A0gAMEUCIDtJIZJDcqIYaDXhZFs0nd0nHER8IGP9n4BBFMWewAb2AiEAlQyavOxw
iTQQxt0rXB4Ox5zWpU9q68+F9BGBkQKTsBs=
-----END CERTIFICATE-----
`
testRevokedCert = `
-----BEGIN CERTIFICATE-----
MIIBYzCCAQigAwIBAgICEAIwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwNzMxMTUzMzE5WjAeMRww
MIIBYjCCAQigAwIBAgICEAIwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAeMRww
GgYDVQQDExNyZXZva2VkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEoN/gKhZgyKhTmiC3qLHDQ54TIpgXBTvGKrdIRHO616XMkzj0lFZMHG5u
LGK3qo8wJtyoalOFTkSck0kl3PD/9qM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
HwYDVR0jBBgwFoAUXep6D8FTP6+5ZdR/HjP3pYfmxkwwCgYIKoZIzj0EAwIDSQAw
RgIhAK6/oLtzvrK2Vrt1MRZJ6aGU2Cz28X0Y/4TOwFSvCK9AAiEAm4XPQXy6L0PE
vfXoV8RW/RnndDhf8iDALvAaAuS82fU=
AQcDQgAEcnoO4EM72C7xL31RE9e6m9YJYyF6E4JloASECd8mdiXPlMXIjq8MZHB5
28mFAVQNE7erAtBftID1SbuY4IpXxqM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
HwYDVR0jBBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwCgYIKoZIzj0EAwIDSAAw
RQIgUUETSO064YIu+VKnyRb0yBnNTjXLy3TvGuYgZI8VX0YCIQDd0gyNEC5YLvRN
njxfnLoimp+TzTVzvsCokUbNSNRKJA==
-----END CERTIFICATE-----
`
testCRL = `
-----BEGIN X509 CRL-----
MIHfMIGFAgEBMAoGCCqGSM49BAMCMBoxGDAWBgNVBAMTD1RydXN0ZWQgUm9vdCBD
QRgPMDAwMTAxMDEwMDAwMDBaMBUwEwICEAIXDTIzMDgwMzE1MzMxOVqgMDAuMB8G
A1UdIwQYMBaAFF3qeg/BUz+vuWXUfx4z96WH5sZMMAsGA1UdFAQEAgIgADAKBggq
hkjOPQQDAgNJADBGAiEApMG/hJxlMe9QNF8cCVjOFyTfVVBkfKtrFQDmElO46x4C
IQCX9SYteNaaW+NVmGED6QfHXRWnDqHnXfe/mLxmnPVWzA==
MIHeMIGFAgEBMAoGCCqGSM49BAMCMBoxGDAWBgNVBAMTD1RydXN0ZWQgUm9vdCBD
QRgPMDAwMTAxMDEwMDAwMDBaMBUwEwICEAIXDTIzMDgxMDE4MDMyMVqgMDAuMB8G
A1UdIwQYMBaAFCRhVVNlDrzlYGmPWHAlIrpxqYgkMAsGA1UdFAQEAgIgADAKBggq
hkjOPQQDAgNIADBFAiEAumtTtjiQt1VsbsEnyr+xbpK0KmzKvkpxIVgE1M9CND0C
IA8zx5clcaGIT5xRnBLZW7RwA37IOmB+7zjAuJQpmKKp
-----END X509 CRL-----
`
testIntermediateCA = `
-----BEGIN CERTIFICATE-----
MIIBkTCCATegAwIBAgICEAMwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAiMSAw
HgYDVQQDExdUcnVzdGVkIEludGVybWVkaWF0ZSBDQTBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABMY+zxL/2dNORuha3uVVOXZYIkTpa9V8N9UVrM15HOHkrdLlz1qk
4wbePkkoGtNRzoayb0iZqeA4YjOxqyPG8emjYzBhMA4GA1UdDwEB/wQEAwIBBjAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQpGNmcLLM3vHiOADYGPDQL8AhkyDAf
BgNVHSMEGDAWgBQkYVVTZQ685WBpj1hwJSK6camIJDAKBggqhkjOPQQDAgNIADBF
AiEAnR6xrk7OCk91ymtzU+duZXDqDq35w0oO+MM8nqpac4YCIED+6c9dJKvRCc/C
nP8PMxRaUsbQet1woE7Fckn5tK4N
-----END CERTIFICATE-----
`
testValidIntermediateCert = `
-----BEGIN CERTIFICATE-----
MIIBdTCCARqgAwIBAgICEAAwCgYIKoZIzj0EAwIwIjEgMB4GA1UEAxMXVHJ1c3Rl
ZCBJbnRlcm1lZGlhdGUgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zMzA4MDcxODAz
MjFaMCgxJjAkBgNVBAMTHWNsaWVudCBjZXJ0IGZyb20gaW50ZXJtZWRpYXRlMFkw
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5SVyYjNRuuFXGjEmCcuVtMq7e2bmndPK
bRJ7lJ5cc0kZSoNJes5wXOtGRFbx3+admRHq+w1XEBXOe+yRUB8kdKM4MDYwEwYD
VR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0jBBgwFoAUKRjZnCyzN7x4jgA2Bjw0C/AI
ZMgwCgYIKoZIzj0EAwIDSQAwRgIhAMj0O2wDRLoxGIPUDOmUfYxmxglOecQhSkWO
NBtItSxmAiEAy0XCzvpL6XOZU3zxyCjTdJQa2RiC6YnypMaCaETzCaU=
-----END CERTIFICATE-----
`
testValidCertWithDNSSANs = `
-----BEGIN CERTIFICATE-----
MIIBlTCCATugAwIBAgICEAQwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAYMRYw
FAYDVQQDEw1jbGllbnQgY2VydCAzMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
LFai39b7TYauNjg4M58f0qY6jTC7xEOhE84wTTcevZvH/t2Y7U0BBNGkvpb14yxh
60vrRKZA9t9G6ZvWKcY/BKNxMG8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
BBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwNwYDVR0RBDAwLoIVYS5jbGllbnQz
LmV4YW1wbGUuY29tghViLmNsaWVudDMuZXhhbXBsZS5jb20wCgYIKoZIzj0EAwID
SAAwRQIgBSw8MsKWPPcpGtuVpNJonTEthIOjIGXswxiYG49y2BECIQC5D1DCX/lY
KSwF4aapPx4906VujTL+Ehj8L5ImUYcPbA==
-----END CERTIFICATE-----
`
testValidCertWithEmailSAN = `
-----BEGIN CERTIFICATE-----
MIIBezCCASKgAwIBAgICEAUwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAYMRYw
FAYDVQQDEw1jbGllbnQgY2VydCA0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
WvX8BnCrzUSpLrYka8ed+bz6/HoXUvq5nRqysKe0nGYSsXKRjxLdCG8AKsoGIQIv
KOQScf/4TJUNIUY4XOsFI6NYMFYwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
BBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwHgYDVR0RBBcwFYETY2xpZW50NEBl
eGFtcGxlLmNvbTAKBggqhkjOPQQDAgNHADBEAiAMYGTjUBqgnai8UL3B/iQkCkMb
xgCC1ZYdZaJ1RBwFfgIgIhjQZ2s6dTaah/LzYJ9ZwMvSA86XQvzTVSuT6s+RJw0=
-----END CERTIFICATE-----
`
testValidCertWithIPSAN = `
-----BEGIN CERTIFICATE-----
MIIBbTCCAROgAwIBAgICEAYwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAYMRYw
FAYDVQQDEw1jbGllbnQgY2VydCA1MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
6+9BE+aomrR2Mdnx4iFY63t0hsVD6rYaHBW1b9roFQX6Cor4YeUfkEEF4LrGeAyb
wcqb6G1ExgNyjEh10Ai1M6NJMEcwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
BBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwDwYDVR0RBAgwBocEwKgKCjAKBggq
hkjOPQQDAgNIADBFAiEA/mq32YZZAacOH/P/wjvfD1n74DD/GkhW4kfS72Z0oGQC
IAQ+L8E78JOLaPWXiL7WFpVrb0hOHkV2m9Qw4GB41mUN
-----END CERTIFICATE-----
`
testValidCertWithURISAN = `
-----BEGIN CERTIFICATE-----
MIIBhTCCASugAwIBAgICEAcwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA3MTgwMzIxWjAYMRYw
FAYDVQQDEw1jbGllbnQgY2VydCA2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
7mHladapSY5PlVYToL1dHr0tJPGe5XVP8DSZJz+WWyS9tWsuEsK6P5yeZrbWASOX
foH7iVIdx3DMyukGsvMX+KNhMF8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0j
BBgwFoAUJGFVU2UOvOVgaY9YcCUiunGpiCQwJwYDVR0RBCAwHoYcc3BpZmZlOi8v
ZXhhbXBsZS5jb20vZm9vL2JhcjAKBggqhkjOPQQDAgNIADBFAiAhzElKeGJzp2zP
GOTUEy0f6b2tvMYGDLQxCcp4bc4QuQIhAPwX4Y3Cr7uazQlbwL6D51y9NCcDyj3D
Z18vZNxm9ZR1
-----END CERTIFICATE-----
`
)
func Test_isValidClientCertificate(t *testing.T) {
t.Parallel()
var noConstraints ClientCertConstraints
t.Run("no ca", func(t *testing.T) {
valid, err := isValidClientCertificate("", "", ClientCertificateInfo{Leaf: "WHATEVER!"})
valid, err := isValidClientCertificate(
"", "", ClientCertificateInfo{Leaf: "WHATEVER!"}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
})
t.Run("no cert", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{})
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
@ -86,7 +169,33 @@ func Test_isValidClientCertificate(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCert,
})
}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
})
t.Run("valid cert with intermediate", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidIntermediateCert,
Intermediates: testIntermediateCA,
}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
})
t.Run("valid cert missing intermediate", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidIntermediateCert,
Intermediates: "",
}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
t.Run("intermediate CA as root", func(t *testing.T) {
valid, err := isValidClientCertificate(testIntermediateCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidIntermediateCert,
}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
})
@ -94,7 +203,7 @@ func Test_isValidClientCertificate(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testUntrustedCert,
})
}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
@ -102,7 +211,7 @@ func Test_isValidClientCertificate(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: "WHATEVER!",
})
}, noConstraints)
assert.Error(t, err, "should return an error")
assert.False(t, valid, "should return false")
})
@ -113,11 +222,11 @@ func Test_isValidClientCertificate(t *testing.T) {
}
// The "revoked cert" should otherwise be valid (when no CRL is specified).
valid, err := isValidClientCertificate(testCA, "", revokedCertInfo)
valid, err := isValidClientCertificate(testCA, "", revokedCertInfo, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
valid, err = isValidClientCertificate(testCA, testCRL, revokedCertInfo)
valid, err = isValidClientCertificate(testCA, testCRL, revokedCertInfo, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
@ -125,8 +234,231 @@ func Test_isValidClientCertificate(t *testing.T) {
valid, err = isValidClientCertificate(testCA, testCRL, ClientCertificateInfo{
Presented: true,
Leaf: testValidCert,
})
}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
})
t.Run("missing CRL", func(t *testing.T) {
// If a CRL is provided for any CA, it must be provided for all CAs.
valid, err := isValidClientCertificate(testCA, testCRL, ClientCertificateInfo{
Presented: true,
Leaf: testValidIntermediateCert,
Intermediates: testIntermediateCA,
}, noConstraints)
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
t.Run("chain too deep", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidIntermediateCert,
Intermediates: testIntermediateCA,
}, ClientCertConstraints{MaxVerifyDepth: 1})
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
t.Run("any SAN", func(t *testing.T) {
matchAnySAN := ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeDNS: regexp.MustCompile("^.*$"),
config.SANTypeEmail: regexp.MustCompile("^.*$"),
config.SANTypeIPAddress: regexp.MustCompile("^.*$"),
config.SANTypeURI: regexp.MustCompile("^.*$"),
}}
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCert, // no SANs
}, matchAnySAN)
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithDNSSANs,
}, matchAnySAN)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithEmailSAN,
}, matchAnySAN)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithIPSAN,
}, matchAnySAN)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithURISAN,
}, matchAnySAN)
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
})
t.Run("DNS SAN", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithDNSSANs,
}, ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeDNS: regexp.MustCompile(`^a\..*\.example\.com$`),
}})
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithDNSSANs,
}, ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeEmail: regexp.MustCompile(`^a\..*\.example\.com$`), // mismatched type
}})
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
t.Run("email SAN", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithEmailSAN,
}, ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeEmail: regexp.MustCompile(`^.*@example\.com$`),
}})
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithEmailSAN,
}, ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeIPAddress: regexp.MustCompile(`^.*@example\.com$`), // mismatched type
}})
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
t.Run("IP address SAN", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithIPSAN,
}, ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeIPAddress: regexp.MustCompile(`^192\.168\.10\..*$`),
}})
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithIPSAN,
}, ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeURI: regexp.MustCompile(`^192\.168\.10\..*$`), // mismatched type
}})
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
t.Run("URI SAN", func(t *testing.T) {
valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithURISAN,
}, ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeURI: regexp.MustCompile(`^spiffe://example\.com/.*$`),
}})
assert.NoError(t, err, "should not return an error")
assert.True(t, valid, "should return true")
valid, err = isValidClientCertificate(testCA, "", ClientCertificateInfo{
Presented: true,
Leaf: testValidCertWithURISAN,
}, ClientCertConstraints{SANMatchers: SANMatchers{
config.SANTypeDNS: regexp.MustCompile(`^spiffe://example\.com/.*$`), // mismatched type
}})
assert.NoError(t, err, "should not return an error")
assert.False(t, valid, "should return false")
})
}
func TestClientCertConstraintsFromConfig(t *testing.T) {
t.Parallel()
t.Run("default constraints", func(t *testing.T) {
var s config.DownstreamMTLSSettings
c, err := ClientCertConstraintsFromConfig(&s)
assert.NoError(t, err)
assert.Equal(t, &ClientCertConstraints{MaxVerifyDepth: 1}, c)
})
t.Run("no constraints", func(t *testing.T) {
s := config.DownstreamMTLSSettings{
MaxVerifyDepth: new(uint32),
}
c, err := ClientCertConstraintsFromConfig(&s)
assert.NoError(t, err)
assert.Equal(t, &ClientCertConstraints{}, c)
})
t.Run("larger max depth", func(t *testing.T) {
depth := uint32(5)
s := config.DownstreamMTLSSettings{
MaxVerifyDepth: &depth,
}
c, err := ClientCertConstraintsFromConfig(&s)
assert.NoError(t, err)
assert.Equal(t, &ClientCertConstraints{MaxVerifyDepth: 5}, c)
})
t.Run("one SAN match", func(t *testing.T) {
s := config.DownstreamMTLSSettings{
MatchSubjectAltNames: []config.SANMatcher{
{Type: config.SANTypeDNS, Pattern: `.*\.corp\.example\.com`},
},
}
c, err := ClientCertConstraintsFromConfig(&s)
assert.NoError(t, err)
assert.Equal(t, &ClientCertConstraints{
MaxVerifyDepth: 1,
SANMatchers: SANMatchers{
config.SANTypeDNS: regexp.MustCompile(`^(.*\.corp\.example\.com)$`),
},
}, c)
})
t.Run("multiple SAN matches", func(t *testing.T) {
s := config.DownstreamMTLSSettings{
MatchSubjectAltNames: []config.SANMatcher{
{Type: config.SANTypeDNS, Pattern: `.*\.foo\.example\.com`},
{Type: config.SANTypeDNS, Pattern: `.*\.bar\.example\.com`},
},
}
c, err := ClientCertConstraintsFromConfig(&s)
assert.NoError(t, err)
assert.Equal(t, &ClientCertConstraints{
MaxVerifyDepth: 1,
SANMatchers: SANMatchers{
config.SANTypeDNS: regexp.MustCompile(`^(.*\.foo\.example\.com)|(.*\.bar\.example\.com)$`),
},
}, c)
})
t.Run("multiple SAN matches", func(t *testing.T) {
s := config.DownstreamMTLSSettings{
MatchSubjectAltNames: []config.SANMatcher{
{Type: config.SANTypeDNS, Pattern: `.*\.foo\.example\.com`},
{Type: config.SANTypeEmail, Pattern: `.*@example\.com`},
},
}
c, err := ClientCertConstraintsFromConfig(&s)
assert.NoError(t, err)
assert.Equal(t, &ClientCertConstraints{
MaxVerifyDepth: 1,
SANMatchers: SANMatchers{
config.SANTypeDNS: regexp.MustCompile(`^(.*\.foo\.example\.com)$`),
config.SANTypeEmail: regexp.MustCompile(`^(.*@example\.com)$`),
},
}, c)
})
t.Run("bad SAN match expression", func(t *testing.T) {
s := config.DownstreamMTLSSettings{
MatchSubjectAltNames: []config.SANMatcher{
{Type: config.SANTypeDNS, Pattern: "["},
},
}
_, err := ClientCertConstraintsFromConfig(&s)
require.Error(t, err)
})
}

View file

@ -12,6 +12,8 @@ import (
"fmt"
"log"
"math/big"
"net"
"net/url"
"time"
)
@ -90,6 +92,26 @@ func main() {
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
intermediatePEM, intermediateCA, intermediateKey := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1003),
Subject: pkix.Name{
CommonName: "Trusted Intermediate CA",
},
NotAfter: notAfter,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
BasicConstraintsValid: true,
IsCA: true,
}, rootCA, rootKey)
trustedClientCert2PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1000),
Subject: pkix.Name{
CommonName: "client cert from intermediate",
},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, intermediateCA, intermediateKey)
_, untrustedCA, untrustedCAKey := newSelfSignedCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1000),
Subject: pkix.Name{
@ -128,6 +150,46 @@ func main() {
},
}, rootCA, rootKey)
trustedClientCert3PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1004),
Subject: pkix.Name{
CommonName: "client cert 3",
},
DNSNames: []string{"a.client3.example.com", "b.client3.example.com"},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
trustedClientCert4PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1005),
Subject: pkix.Name{
CommonName: "client cert 4",
},
EmailAddresses: []string{"client4@example.com"},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
trustedClientCert5PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1006),
Subject: pkix.Name{
CommonName: "client cert 5",
},
IPAddresses: []net.IP{net.ParseIP("192.168.10.10")},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
trustedClientCert6PEM, _, _ := newCertificate(&x509.Certificate{
SerialNumber: big.NewInt(0x1007),
Subject: pkix.Name{
CommonName: "client cert 6",
},
URIs: []*url.URL{{Scheme: "spiffe", Host: "example.com", Path: "/foo/bar"}},
NotAfter: notAfter,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}, rootCA, rootKey)
fmt.Println(`
const (
testCA = ` + "`\n" + rootPEM + "`" + `
@ -135,6 +197,12 @@ const (
testUntrustedCert = ` + "`\n" + untrustedClientCertPEM + "`" + `
testRevokedCert = ` + "`\n" + revokedClientCertPEM + "`" + `
testCRL = ` + "`\n" + crlPEM + "`" + `
testIntermediateCA = ` + "`\n" + intermediatePEM + "`" + `
testValidIntermediateCert = ` + "`\n" + trustedClientCert2PEM + "`" + `
testValidCertWithDNSSANs = ` + "`\n" + trustedClientCert3PEM + "`" + `
testValidCertWithEmailSAN = ` + "`\n" + trustedClientCert4PEM + "`" + `
testValidCertWithIPSAN = ` + "`\n" + trustedClientCert5PEM + "`" + `
testValidCertWithURISAN = ` + "`\n" + trustedClientCert6PEM + "`" + `
)
`)
}

View file

@ -17,21 +17,22 @@ import (
// HeadersRequest is the input to the headers.rego script.
type HeadersRequest struct {
EnableGoogleCloudServerlessAuthentication bool `json:"enable_google_cloud_serverless_authentication"`
EnableRoutingKey bool `json:"enable_routing_key"`
Issuer string `json:"issuer"`
KubernetesServiceAccountToken string `json:"kubernetes_service_account_token"`
ToAudience string `json:"to_audience"`
Session RequestSession `json:"session"`
PassAccessToken bool `json:"pass_access_token"`
PassIDToken bool `json:"pass_id_token"`
SetRequestHeaders map[string]string `json:"set_request_headers"`
EnableGoogleCloudServerlessAuthentication bool `json:"enable_google_cloud_serverless_authentication"`
EnableRoutingKey bool `json:"enable_routing_key"`
Issuer string `json:"issuer"`
KubernetesServiceAccountToken string `json:"kubernetes_service_account_token"`
ToAudience string `json:"to_audience"`
Session RequestSession `json:"session"`
ClientCertificate ClientCertificateInfo `json:"client_certificate"`
PassAccessToken bool `json:"pass_access_token"`
PassIDToken bool `json:"pass_id_token"`
SetRequestHeaders map[string]string `json:"set_request_headers"`
}
// NewHeadersRequestFromPolicy creates a new HeadersRequest from a policy.
func NewHeadersRequestFromPolicy(policy *config.Policy, hostname string) *HeadersRequest {
func NewHeadersRequestFromPolicy(policy *config.Policy, http RequestHTTP) *HeadersRequest {
input := new(HeadersRequest)
input.Issuer = hostname
input.Issuer = http.Hostname
if policy != nil {
input.EnableGoogleCloudServerlessAuthentication = policy.EnableGoogleCloudServerlessAuthentication
input.EnableRoutingKey = policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_RING_HASH ||
@ -42,6 +43,7 @@ func NewHeadersRequestFromPolicy(policy *config.Policy, hostname string) *Header
}
input.PassAccessToken = policy.GetSetAuthorizationHeader() == configpb.Route_ACCESS_TOKEN
input.PassIDToken = policy.GetSetAuthorizationHeader() == configpb.Route_ID_TOKEN
input.ClientCertificate = http.ClientCertificate
input.SetRequestHeaders = policy.SetRequestHeaders
}
return input

View file

@ -34,16 +34,24 @@ func TestNewHeadersRequestFromPolicy(t *testing.T) {
URL: *mustParseURL("http://to.example.com"),
},
},
}, "from.example.com")
}, RequestHTTP{
Hostname: "from.example.com",
ClientCertificate: ClientCertificateInfo{
Leaf: "--- FAKE CERTIFICATE ---",
},
})
assert.Equal(t, &HeadersRequest{
EnableGoogleCloudServerlessAuthentication: true,
Issuer: "from.example.com",
ToAudience: "https://to.example.com",
ClientCertificate: ClientCertificateInfo{
Leaf: "--- FAKE CERTIFICATE ---",
},
}, req)
}
func TestNewHeadersRequestFromPolicy_nil(t *testing.T) {
req := NewHeadersRequestFromPolicy(nil, "from.example.com")
req := NewHeadersRequestFromPolicy(nil, RequestHTTP{Hostname: "from.example.com"})
assert.Equal(t, &HeadersRequest{
Issuer: "from.example.com",
}, req)
@ -184,16 +192,20 @@ func TestHeadersEvaluator(t *testing.T) {
ToAudience: "to.example.com",
Session: RequestSession{ID: "s1"},
SetRequestHeaders: map[string]string{
"X-Custom-Header": "CUSTOM_VALUE",
"X-ID-Token": "$pomerium.id_token",
"X-Access-Token": "$pomerium.access_token",
"X-Custom-Header": "CUSTOM_VALUE",
"X-ID-Token": "$pomerium.id_token",
"X-Access-Token": "$pomerium.access_token",
"Client-Cert-Fingerprint": "$pomerium.client_cert_fingerprint",
},
ClientCertificate: ClientCertificateInfo{Leaf: testValidCert},
})
require.NoError(t, err)
assert.Equal(t, "CUSTOM_VALUE", output.Headers.Get("X-Custom-Header"))
assert.Equal(t, "ID_TOKEN", output.Headers.Get("X-ID-Token"))
assert.Equal(t, "ACCESS_TOKEN", output.Headers.Get("X-Access-Token"))
assert.Equal(t, "ebf421e323e31c3900a7985a16e72c59f45f5a2c15283297567e226b3b17d1a1",
output.Headers.Get("Client-Cert-Fingerprint"))
})
t.Run("set_request_headers original behavior", func(t *testing.T) {
@ -217,6 +229,20 @@ func TestHeadersEvaluator(t *testing.T) {
assert.Equal(t, "Bearer ID_TOKEN", output.Headers.Get("Authorization"))
})
t.Run("set_request_headers no client cert", func(t *testing.T) {
output, err := eval(t, nil,
&HeadersRequest{
Issuer: "from.example.com",
ToAudience: "to.example.com",
SetRequestHeaders: map[string]string{
"fingerprint": "$pomerium.client_cert_fingerprint",
},
})
require.NoError(t, err)
assert.Equal(t, "", output.Headers.Get("fingerprint"))
})
}
func decodeJWSPayload(t *testing.T, jws string) []byte {

View file

@ -3,6 +3,8 @@ package pomerium.headers
# input:
# enable_google_cloud_serverless_authentication: boolean
# enable_routing_key: boolean
# client_certificate:
# leaf: string
# issuer: string
# kubernetes_service_account_token: string
# session:
@ -211,13 +213,19 @@ session_access_token = v {
v := session.oauth_token.access_token
} else = ""
client_cert_fingerprint = v {
cert := crypto.x509.parse_certificates(trim_space(input.client_certificate.leaf))[0]
v := crypto.sha256(base64.decode(cert.Raw))
} else = ""
set_request_headers = h {
h := [[header_name, header_value] |
some header_name
v1 := input.set_request_headers[header_name]
v2 := replace(v1, "$pomerium.id_token", session_id_token)
v3 := replace(v2, "$pomerium.access_token", session_access_token)
header_value := v3
v4 := replace(v3, "$pomerium.client_cert_fingerprint", client_cert_fingerprint)
header_value := v4
]
} else = []

View file

@ -108,13 +108,14 @@ type PolicyEvaluator struct {
// NewPolicyEvaluator creates a new PolicyEvaluator.
func NewPolicyEvaluator(
ctx context.Context, store *store.Store, configPolicy *config.Policy, clientCA string,
ctx context.Context, store *store.Store, configPolicy *config.Policy,
addDefaultClientCertificateRule bool,
) (*PolicyEvaluator, error) {
e := new(PolicyEvaluator)
// generate the base rego script for the policy
ppl := configPolicy.ToPPL()
if clientCA != "" {
if addDefaultClientCertificateRule {
ppl.AddDefaultClientCertificateRule()
}
base, err := policy.GenerateRegoFromPolicy(ppl)

View file

@ -32,7 +32,7 @@ func TestPolicyEvaluator(t *testing.T) {
privateJWK, err := cryptutil.PrivateJWKFromBytes(encodedSigningKey)
require.NoError(t, err)
var clientCA string
var addDefaultClientCertificateRule bool
eval := func(t *testing.T, policy *config.Policy, data []proto.Message, input *PolicyRequest) (*PolicyResponse, error) {
ctx := context.Background()
@ -40,7 +40,7 @@ func TestPolicyEvaluator(t *testing.T) {
store := store.New()
store.UpdateJWTClaimHeaders(config.NewJWTClaimHeaders("email", "groups", "user", "CUSTOM_KEY"))
store.UpdateSigningKey(privateJWK)
e, err := NewPolicyEvaluator(ctx, store, policy, clientCA)
e, err := NewPolicyEvaluator(ctx, store, policy, addDefaultClientCertificateRule)
require.NoError(t, err)
return e.Evaluate(ctx, input)
}
@ -99,7 +99,7 @@ func TestPolicyEvaluator(t *testing.T) {
})
// Enable client certificate validation.
clientCA = "---FAKE CA CERTIFICATE---"
addDefaultClientCertificateRule = true
t.Run("allowed with cert", func(t *testing.T) {
output, err := eval(t,

View file

@ -225,12 +225,13 @@ func (src *FileWatcherSource) check(ctx context.Context, cfg *Config) {
cfg.Options.CAFile,
cfg.Options.CertFile,
cfg.Options.ClientCAFile,
cfg.Options.ClientCRLFile,
cfg.Options.ClientSecretFile,
cfg.Options.CookieSecretFile,
cfg.Options.DataBrokerStorageCAFile,
cfg.Options.DataBrokerStorageCertFile,
cfg.Options.DataBrokerStorageCertKeyFile,
cfg.Options.DownstreamMTLS.CAFile,
cfg.Options.DownstreamMTLS.CRLFile,
cfg.Options.KeyFile,
cfg.Options.MetricsCertificateFile,
cfg.Options.MetricsCertificateKeyFile,

View file

@ -517,14 +517,15 @@ func (b *Builder) buildDownstreamTLSContextMulti(
if err != nil {
return nil, err
}
return &envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext{
dtc := &envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext{
CommonTlsContext: &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext{
TlsParams: tlsParams,
TlsCertificates: envoyCerts,
AlpnProtocols: getALPNProtos(cfg.Options),
ValidationContextType: b.buildDownstreamValidationContext(ctx, cfg),
TlsParams: tlsParams,
TlsCertificates: envoyCerts,
AlpnProtocols: getALPNProtos(cfg.Options),
},
}, nil
}
b.buildDownstreamValidationContext(ctx, dtc, cfg)
return dtc, nil
}
func getALPNProtos(opts *config.Options) []string {
@ -540,39 +541,57 @@ func getALPNProtos(opts *config.Options) []string {
func (b *Builder) buildDownstreamValidationContext(
ctx context.Context,
dtc *envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext,
cfg *config.Config,
) *envoy_extensions_transport_sockets_tls_v3.CommonTlsContext_ValidationContext {
) {
clientCA := clientCABundle(ctx, cfg)
if len(clientCA) == 0 {
return nil
return
}
vc := &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext_ValidationContext{
ValidationContext: &envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext{
TrustChainVerification: envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext_ACCEPT_UNTRUSTED,
TrustedCa: b.filemgr.BytesDataSource("client-ca.pem", clientCA),
},
vc := &envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext{
TrustedCa: b.filemgr.BytesDataSource("client-ca.pem", clientCA),
MatchTypedSubjectAltNames: make([]*envoy_extensions_transport_sockets_tls_v3.SubjectAltNameMatcher,
0, len(cfg.Options.DownstreamMTLS.MatchSubjectAltNames)),
}
for i := range cfg.Options.DownstreamMTLS.MatchSubjectAltNames {
vc.MatchTypedSubjectAltNames = append(vc.MatchTypedSubjectAltNames,
cfg.Options.DownstreamMTLS.MatchSubjectAltNames[i].ToEnvoyProto())
}
if cfg.Options.ClientCRL != "" {
bs, err := base64.StdEncoding.DecodeString(cfg.Options.ClientCRL)
if d := cfg.Options.DownstreamMTLS.GetMaxVerifyDepth(); d > 0 {
vc.MaxVerifyDepth = wrapperspb.UInt32(d)
}
if cfg.Options.DownstreamMTLS.GetEnforcement() == config.MTLSEnforcementRejectConnection {
dtc.RequireClientCertificate = wrapperspb.Bool(true)
} else {
vc.TrustChainVerification =
envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext_ACCEPT_UNTRUSTED
}
if crl := cfg.Options.DownstreamMTLS.CRL; crl != "" {
bs, err := base64.StdEncoding.DecodeString(crl)
if err != nil {
log.Error(ctx).Err(err).Msg("invalid client CRL")
} else {
vc.ValidationContext.Crl = b.filemgr.BytesDataSource("client-crl.pem", bs)
vc.Crl = b.filemgr.BytesDataSource("client-crl.pem", bs)
}
} else if cfg.Options.ClientCRLFile != "" {
vc.ValidationContext.Crl = b.filemgr.FileDataSource(cfg.Options.ClientCRLFile)
} else if crlf := cfg.Options.DownstreamMTLS.CRLFile; crlf != "" {
vc.Crl = b.filemgr.FileDataSource(crlf)
}
return vc
dtc.CommonTlsContext.ValidationContextType =
&envoy_extensions_transport_sockets_tls_v3.CommonTlsContext_ValidationContext{
ValidationContext: vc,
}
}
// clientCABundle returns a bundle of the globally configured client CA and any
// per-route client CAs.
func clientCABundle(ctx context.Context, cfg *config.Config) []byte {
var bundle bytes.Buffer
ca, _ := cfg.Options.GetClientCA()
ca, _ := cfg.Options.DownstreamMTLS.GetCA()
addCAToBundle(&bundle, ca)
allPolicies := cfg.Options.GetAllPolicies()
for i := range allPolicies {

View file

@ -98,7 +98,9 @@ func Test_buildDownstreamTLSContext(t *testing.T) {
})
t.Run("client-ca", func(t *testing.T) {
downstreamTLSContext, err := b.buildDownstreamTLSContextMulti(context.Background(), &config.Config{Options: &config.Options{
ClientCA: "VEVTVAo=", // "TEST\n" (with a trailing newline)
DownstreamMTLS: config.DownstreamMTLSSettings{
CA: "VEVTVAo=", // "TEST\n" (with a trailing newline)
},
}}, nil)
require.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `{
@ -116,6 +118,7 @@ func Test_buildDownstreamTLSContext(t *testing.T) {
},
"alpnProtocols": ["h2", "http/1.1"],
"validationContext": {
"maxVerifyDepth": 1,
"trustChainVerification": "ACCEPT_UNTRUSTED",
"trustedCa": {
"filename": "`+clientCAFileName+`"
@ -124,6 +127,38 @@ func Test_buildDownstreamTLSContext(t *testing.T) {
}
}`, downstreamTLSContext)
})
t.Run("client-ca-strict", func(t *testing.T) {
downstreamTLSContext, err := b.buildDownstreamTLSContextMulti(context.Background(), &config.Config{Options: &config.Options{
DownstreamMTLS: config.DownstreamMTLSSettings{
CA: "VEVTVAo=", // "TEST\n" (with a trailing newline)
Enforcement: config.MTLSEnforcementRejectConnection,
},
}}, nil)
require.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `{
"commonTlsContext": {
"tlsParams": {
"cipherSuites": [
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-CHACHA20-POLY1305",
"ECDHE-RSA-CHACHA20-POLY1305"
],
"tlsMinimumProtocolVersion": "TLSv1_2"
},
"alpnProtocols": ["h2", "http/1.1"],
"validationContext": {
"maxVerifyDepth": 1,
"trustedCa": {
"filename": "`+clientCAFileName+`"
}
}
},
"requireClientCertificate": true
}`, downstreamTLSContext)
})
t.Run("policy-client-ca", func(t *testing.T) {
downstreamTLSContext, err := b.buildDownstreamTLSContextMulti(context.Background(), &config.Config{Options: &config.Options{
Policies: []config.Policy{
@ -150,6 +185,7 @@ func Test_buildDownstreamTLSContext(t *testing.T) {
},
"alpnProtocols": ["h2", "http/1.1"],
"validationContext": {
"maxVerifyDepth": 1,
"trustChainVerification": "ACCEPT_UNTRUSTED",
"trustedCa": {
"filename": "`+clientCAFileName+`"
@ -158,6 +194,99 @@ func Test_buildDownstreamTLSContext(t *testing.T) {
}
}`, downstreamTLSContext)
})
t.Run("client-ca-max-verify-depth", func(t *testing.T) {
var maxVerifyDepth uint32
config := &config.Config{Options: &config.Options{
DownstreamMTLS: config.DownstreamMTLSSettings{
MaxVerifyDepth: &maxVerifyDepth,
CA: "VEVTVAo=", // "TEST\n"
},
}}
maxVerifyDepth = 10
downstreamTLSContext, err :=
b.buildDownstreamTLSContextMulti(context.Background(), config, nil)
require.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `{
"maxVerifyDepth": 10,
"trustChainVerification": "ACCEPT_UNTRUSTED",
"trustedCa": {
"filename": "`+clientCAFileName+`"
}
}`, downstreamTLSContext.GetCommonTlsContext().GetValidationContext())
maxVerifyDepth = 0
downstreamTLSContext, err =
b.buildDownstreamTLSContextMulti(context.Background(), config, nil)
require.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `{
"trustChainVerification": "ACCEPT_UNTRUSTED",
"trustedCa": {
"filename": "`+clientCAFileName+`"
}
}`, downstreamTLSContext.GetCommonTlsContext().GetValidationContext())
})
t.Run("client-ca-san-matchers", func(t *testing.T) {
config := &config.Config{Options: &config.Options{
DownstreamMTLS: config.DownstreamMTLSSettings{
CA: "VEVTVAo=", // "TEST\n"
MatchSubjectAltNames: []config.SANMatcher{
{Type: config.SANTypeDNS, Pattern: `.*\.corp\.example\.com`},
{Type: config.SANTypeEmail, Pattern: `.*@example\.com`},
{Type: config.SANTypeIPAddress, Pattern: `10\.10\.42\..*`},
{Type: config.SANTypeURI, Pattern: `spiffe://example\.com/.*`},
},
},
}}
downstreamTLSContext, err :=
b.buildDownstreamTLSContextMulti(context.Background(), config, nil)
require.NoError(t, err)
testutil.AssertProtoJSONEqual(t, `{
"maxVerifyDepth": 1,
"matchTypedSubjectAltNames": [
{
"matcher": {
"safeRegex": {
"googleRe2": {},
"regex": ".*\\.corp\\.example\\.com"
}
},
"sanType": "DNS"
},
{
"matcher": {
"safeRegex": {
"googleRe2": {},
"regex": ".*@example\\.com"
}
},
"sanType": "EMAIL"
},
{
"matcher": {
"safeRegex": {
"googleRe2": {},
"regex": "10\\.10\\.42\\..*"
}
},
"sanType": "IP_ADDRESS"
},
{
"matcher": {
"safeRegex": {
"googleRe2": {},
"regex": "spiffe://example\\.com/.*"
}
},
"sanType": "URI"
}
],
"trustChainVerification": "ACCEPT_UNTRUSTED",
"trustedCa": {
"filename": "`+clientCAFileName+`"
}
}`, downstreamTLSContext.GetCommonTlsContext().GetValidationContext())
})
t.Run("http1", func(t *testing.T) {
downstreamTLSContext, err := b.buildDownstreamTLSContextMulti(context.Background(), &config.Config{Options: &config.Options{
Cert: aExampleComCert,
@ -218,7 +347,9 @@ func Test_clientCABundle(t *testing.T) {
b64 := base64.StdEncoding.EncodeToString
cfg := &config.Config{Options: &config.Options{
ClientCA: b64(clientCA3),
DownstreamMTLS: config.DownstreamMTLSSettings{
CA: b64(clientCA3),
},
Policies: []config.Policy{
{
From: "https://foo.example.com",

278
config/mtls.go Normal file
View file

@ -0,0 +1,278 @@
package config
import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"os"
"regexp"
envoy_tls "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
envoy_matcher "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/grpc/config"
)
// MTLSEnforcement represents a client certificate enforcement behavior.
type MTLSEnforcement string
const (
// MTLSEnforcementPolicy specifies no default client certificate
// enforcement: any requirements must be explicitly specified in a policy.
MTLSEnforcementPolicy MTLSEnforcement = "policy"
// MTLSEnforcementPolicyWithDefaultDeny specifies that client certificate
// requirements will be enforced by route policy, with a default
// invalid_client_certificate deny rule added to each policy.
MTLSEnforcementPolicyWithDefaultDeny MTLSEnforcement = "policy_with_default_deny"
// MTLSEnforcementRejectConnection specifies that client certificate
// requirements will be enforced by rejecting any connection attempts
// without a trusted certificate.
MTLSEnforcementRejectConnection MTLSEnforcement = "reject_connection"
)
// SANType represents a certificate Subject Alternative Name type.
type SANType string
const (
// SANTypeDNS represents a DNS name.
SANTypeDNS SANType = "dns"
// SANTypeEmail represents an email address.
SANTypeEmail SANType = "email"
// SANTypeIPAddress represents an IP address.
SANTypeIPAddress SANType = "ip_address"
// SANTypeURI represents a URI.
SANTypeURI SANType = "uri"
)
// DownstreamMTLSSettings specify the downstream client certificate requirements.
type DownstreamMTLSSettings struct {
// CA is the base64-encoded certificate authority (or bundle of certificate
// authorities) that should serve as the trust root(s). These will be
// advertised in the initial TLS handshake.
CA string `mapstructure:"ca" yaml:"ca"`
// CAFile is the path to a file containing the certificate authority (or
// bundle of certificate authorities) that should serve as the trust
// root(s). These will be advertised in the initial TLS handshake.
CAFile string `mapstructure:"ca_file" yaml:"ca_file"`
// CRL is the base64-encoded certificate revocation list (or bundle of
// CRLs) to use when validating client certificates.
CRL string `mapstructure:"crl" yaml:"crl,omitempty"`
// CRLFile is the path to a file containing the certificate revocation
// list (or bundle of CRLs) to use when validating client certificates.
CRLFile string `mapstructure:"crl_file" yaml:"crl_file,omitempty"`
// Enforcement indicates the behavior applied to requests without a valid
// client certificate.
Enforcement MTLSEnforcement `mapstructure:"enforcement" yaml:"enforcement,omitempty"`
// MatchSubjectAltNames is a list of SAN match expressions. When non-empty,
// a client certificate must contain at least one Subject Alternative Name
// that matches at least one of the expessions.
MatchSubjectAltNames []SANMatcher `mapstructure:"match_subject_alt_names" yaml:"match_subject_alt_names,omitempty"`
// MaxVerifyDepth is the maximum allowed depth of a certificate trust chain
// (not counting the leaf certificate). The value 0 indicates no maximum.
MaxVerifyDepth *uint32 `mapstructure:"max_verify_depth" yaml:"max_verify_depth,omitempty"`
}
// GetCA returns the certificate authority (or nil if unset).
func (s *DownstreamMTLSSettings) GetCA() ([]byte, error) {
if s.CA != "" {
ca, err := base64.StdEncoding.DecodeString(s.CA)
if err != nil {
return nil, fmt.Errorf("CA: %w", err)
}
return ca, nil
}
if s.CAFile != "" {
ca, err := os.ReadFile(s.CAFile)
if err != nil {
return nil, fmt.Errorf("CA file: %w", err)
}
return ca, nil
}
return nil, nil
}
// GetCRL returns the certificate revocation list bundle (or nil if unset).
func (s *DownstreamMTLSSettings) GetCRL() ([]byte, error) {
if s.CRL != "" {
crl, err := base64.StdEncoding.DecodeString(s.CRL)
if err != nil {
return nil, fmt.Errorf("CRL: %w", err)
}
return crl, nil
}
if s.CRLFile != "" {
crl, err := os.ReadFile(s.CRLFile)
if err != nil {
return nil, fmt.Errorf("CRL file: %w", err)
}
return crl, nil
}
return nil, nil
}
// GetEnforcement returns the enforcement behavior to apply.
func (s *DownstreamMTLSSettings) GetEnforcement() MTLSEnforcement {
if s.Enforcement == "" {
return MTLSEnforcementPolicyWithDefaultDeny
}
return s.Enforcement
}
// GetMaxVerifyDepth returns the maximum certificate chain depth. The value 0
// indicates no maximum.
func (s *DownstreamMTLSSettings) GetMaxVerifyDepth() uint32 {
if s.MaxVerifyDepth == nil {
return 1
}
return *s.MaxVerifyDepth
}
func (s *DownstreamMTLSSettings) validate() error {
if s.CA != "" && s.CAFile != "" {
return errors.New("cannot set both ca and ca_file")
} else if _, err := s.GetCA(); err != nil {
return err
}
if s.CRL != "" && s.CRLFile != "" {
return errors.New("cannot set both crl and crl_file")
}
crl, err := s.GetCRL()
if err != nil {
return err
} else if _, err := cryptutil.ParseCRLs(crl); err != nil {
return fmt.Errorf("CRL: %w", err)
}
switch s.Enforcement {
case "",
MTLSEnforcementPolicy,
MTLSEnforcementPolicyWithDefaultDeny,
MTLSEnforcementRejectConnection: // OK
default:
return errors.New("unknown enforcement option")
}
for i := range s.MatchSubjectAltNames {
if err := s.MatchSubjectAltNames[i].validate(); err != nil {
return err
}
}
return nil
}
func (s *DownstreamMTLSSettings) applySettingsProto(
ctx context.Context, p *config.DownstreamMtlsSettings,
) {
if p == nil {
return
}
set(&s.CA, p.Ca)
set(&s.CRL, p.Crl)
s.Enforcement = mtlsEnforcementFromProtoEnum(ctx, p.Enforcement)
}
func mtlsEnforcementFromProtoEnum(
ctx context.Context, mode *config.MtlsEnforcementMode,
) MTLSEnforcement {
if mode == nil {
return ""
}
switch *mode {
case config.MtlsEnforcementMode_POLICY:
return MTLSEnforcementPolicy
case config.MtlsEnforcementMode_POLICY_WITH_DEFAULT_DENY:
return MTLSEnforcementPolicyWithDefaultDeny
case config.MtlsEnforcementMode_REJECT_CONNECTION:
return MTLSEnforcementRejectConnection
default:
log.Error(ctx).Msgf("unknown mTLS enforcement mode %s", mode)
return ""
}
}
// SANMatcher represents a Subject Alternative Name string matcher condition. A
// certificate satisfies this condition if it contains at least one SAN of the
// given type that matches the regular expression as a full string match.
type SANMatcher struct {
Type SANType
Pattern string
}
func (s *SANMatcher) validate() error {
if s.envoyType() == envoy_tls.SubjectAltNameMatcher_SAN_TYPE_UNSPECIFIED {
return fmt.Errorf("unknown SAN type %q", s.Type)
}
if _, err := regexp.Compile(s.Pattern); err != nil {
return fmt.Errorf("couldn't parse pattern %q: %w", s.Pattern, err)
}
return nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (s *SANMatcher) UnmarshalJSON(b []byte) error {
var m map[string]string
if err := json.Unmarshal(b, &m); err != nil {
return err
} else if len(m) != 1 {
return errors.New("unsupported SAN matcher format: expected {type: pattern}")
}
for k, v := range m {
s.Type = SANType(k)
s.Pattern = v
}
return nil
}
// MarshalJSON implements the json.Marshaler interface.
func (s *SANMatcher) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]string{string(s.Type): s.Pattern})
}
// ToEnvoyProto rerturns a representation of this matcher as an Envoy
// SubjectAltNameMatcher proto.
func (s *SANMatcher) ToEnvoyProto() *envoy_tls.SubjectAltNameMatcher {
return &envoy_tls.SubjectAltNameMatcher{
SanType: s.envoyType(),
Matcher: &envoy_matcher.StringMatcher{
MatchPattern: &envoy_matcher.StringMatcher_SafeRegex{
SafeRegex: &envoy_matcher.RegexMatcher{
EngineType: &envoy_matcher.RegexMatcher_GoogleRe2{},
Regex: s.Pattern,
},
},
},
}
}
func (s *SANMatcher) envoyType() envoy_tls.SubjectAltNameMatcher_SanType {
switch s.Type {
case SANTypeDNS:
return envoy_tls.SubjectAltNameMatcher_DNS
case SANTypeEmail:
return envoy_tls.SubjectAltNameMatcher_EMAIL
case SANTypeIPAddress:
return envoy_tls.SubjectAltNameMatcher_IP_ADDRESS
case SANTypeURI:
return envoy_tls.SubjectAltNameMatcher_URI
default:
return envoy_tls.SubjectAltNameMatcher_SAN_TYPE_UNSPECIFIED
}
}

169
config/mtls_test.go Normal file
View file

@ -0,0 +1,169 @@
package config
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDownstreamMTLSSettingsGetCA(t *testing.T) {
t.Parallel()
fakeCACert := []byte("--- FAKE CA CERT ---")
caFile := filepath.Join(t.TempDir(), "CA.pem")
os.WriteFile(caFile, fakeCACert, 0644)
cases := []struct {
label string
settings DownstreamMTLSSettings
expected []byte
}{
{"not set", DownstreamMTLSSettings{}, nil},
{"CA", DownstreamMTLSSettings{CA: "LS0tIEZBS0UgQ0EgQ0VSVCAtLS0="}, fakeCACert},
{"CA file", DownstreamMTLSSettings{CAFile: caFile}, fakeCACert},
}
for i := range cases {
c := &cases[i]
t.Run(c.label, func(t *testing.T) {
ca, err := c.settings.GetCA()
require.NoError(t, err)
assert.Equal(t, c.expected, ca)
})
}
}
func TestDownstreamMTLSSettingsGetCRL(t *testing.T) {
t.Parallel()
fakeCRL := []byte("--- FAKE CRL ---")
crlFile := filepath.Join(t.TempDir(), "CRL.pem")
os.WriteFile(crlFile, fakeCRL, 0644)
cases := []struct {
label string
settings DownstreamMTLSSettings
expected []byte
}{
{"not set", DownstreamMTLSSettings{}, nil},
{"CRL", DownstreamMTLSSettings{CRL: "LS0tIEZBS0UgQ1JMIC0tLQ=="}, fakeCRL},
{"CRL file", DownstreamMTLSSettings{CRLFile: crlFile}, fakeCRL},
}
for i := range cases {
c := &cases[i]
t.Run(c.label, func(t *testing.T) {
crl, err := c.settings.GetCRL()
require.NoError(t, err)
assert.Equal(t, c.expected, crl)
})
}
}
func TestDownstreamMTLSSettingsGetEnforcement(t *testing.T) {
t.Parallel()
cases := []struct {
label string
settings DownstreamMTLSSettings
expected MTLSEnforcement
}{
{"default",
DownstreamMTLSSettings{}, MTLSEnforcementPolicyWithDefaultDeny,
},
{"policy",
DownstreamMTLSSettings{Enforcement: "policy"}, MTLSEnforcementPolicy,
},
{"policy_with_default_deny",
DownstreamMTLSSettings{Enforcement: "policy_with_default_deny"},
MTLSEnforcementPolicyWithDefaultDeny,
},
{"reject_connection",
DownstreamMTLSSettings{Enforcement: "reject_connection"},
MTLSEnforcementRejectConnection,
},
}
for i := range cases {
c := &cases[i]
t.Run(c.label, func(t *testing.T) {
assert.Equal(t, c.expected, c.settings.GetEnforcement())
})
}
}
func TestDownstreamMTLSSettingsGetMaxVerifyDepth(t *testing.T) {
t.Parallel()
// MaxVerifyDepth should default to 1 if not set explicitly.
var s DownstreamMTLSSettings
assert.Equal(t, uint32(1), s.GetMaxVerifyDepth())
var maxVerifyDepth uint32
s.MaxVerifyDepth = &maxVerifyDepth
assert.Equal(t, uint32(0), s.GetMaxVerifyDepth())
maxVerifyDepth = 1
assert.Equal(t, uint32(1), s.GetMaxVerifyDepth())
maxVerifyDepth = 1000
assert.Equal(t, uint32(1000), s.GetMaxVerifyDepth())
}
func TestDownstreamMTLSSettingsValidate(t *testing.T) {
t.Parallel()
cases := []struct {
label string
settings DownstreamMTLSSettings
errorMsg string
}{
{"not set", DownstreamMTLSSettings{}, ""},
{"both CA and CA file", DownstreamMTLSSettings{CA: "CA", CAFile: "CAFile"},
"cannot set both ca and ca_file"},
{"bad CA", DownstreamMTLSSettings{CA: "not%valid%base64%data"},
"CA: illegal base64 data at input byte 3"},
{"bad CA file", DownstreamMTLSSettings{CAFile: "-"},
"CA file: open -: no such file or directory"},
{"both CRL and CRL file", DownstreamMTLSSettings{CRL: "CRL", CRLFile: "CRLFile"},
"cannot set both crl and crl_file"},
{"bad CRL", DownstreamMTLSSettings{CRL: "dGhpc2lzZmluZQo="},
"CRL: cryptutil: non-PEM data in CRL bundle"},
{"bad CRL file", DownstreamMTLSSettings{CRLFile: "-"},
"CRL file: open -: no such file or directory"},
{"bad enforcement mode", DownstreamMTLSSettings{Enforcement: "whatever"},
"unknown enforcement option"},
{"bad SAN type", DownstreamMTLSSettings{MatchSubjectAltNames: []SANMatcher{
{Type: "whatever"},
}}, `unknown SAN type "whatever"`},
{"bad SAN match expression", DownstreamMTLSSettings{MatchSubjectAltNames: []SANMatcher{
{Type: "dns", Pattern: `[`},
}}, "couldn't parse pattern \"[\": error parsing regexp: missing closing ]: `[`"},
{"OK", DownstreamMTLSSettings{
CA: "dGhpc2lzZmluZQo=",
CRL: "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNOVENCbmdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTWhjTk1qTXdOekU1TWpFMQpNREUxV2hjTk16TXdOekUyTWpFMU1ERTFXcUF3TUM0d0h3WURWUjBqQkJnd0ZvQVVDeFEyY0JhNVl6cVZ6YW1wCmlOQ3g4S3dGRnlRd0N3WURWUjBVQkFRQ0FoQUFNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJnUUNZYW14OHBNK1IKQ2x5c2tjdTdvdWh1L1IxSnkxbldHeVd0S3BoWXEwWEZiT0xsbmsyWjdlRGZBWDhFZWoyRmF2cXh6YXBSMngyTwo0aUpORENtaXdZWVlVUzJYMkxKM3JSUkpYeVh2V2h0ZkhyeFVSZDZCaXRDMklYcHlrQnRWbGYzekFuWjhHWkZRClMxamRmeUxNdUVBaUR3SWFpM1l0OEhzRHAvcUcwODlvWGNvU3R5UWcvdVJwbVd5MDVBOXVDVk9mTkhTTFNadTgKbHI0cWF0bGV1MHdXYlYxYW1MOHRPOXg0Q1JrTzBvMVlhUXE0RG9PcnVQciszTmtUbVB2R2lkaDNGNzFWNklFQQpoK0t6ZGJSWHhGbUNDV0xXbXBKRGNyZ1I3S1VxWk9oVVV0K0RVcWFxaFY0NHFJMG5ycFIrUVpMb2hvRG9yOUx3CksrdWZqM24yOWVTUlgrM1B4K29WV1BUOFlaUDJ1S1BkaXppOTZtZTJqV1RyNTF4OUFqRW9KRHNUbllSbDkrdVkKU2hpVXhXblRkUXNvb2tuSWZjUy8wemZnWjg3R3ZVVnppbkNRekpwd1Z4ZDRBbHQ4QWxSK2ZYQXFOSW9PZ3V5dgpwL0N0UlZualZFN2w3SFcvaFFScTFKMGlqQ0NLd215Zi9LVGQ2RUs0VGRydmJYL1U5bXNWTThZPQotLS0tLUVORCBYNTA5IENSTC0tLS0tCg==",
Enforcement: "reject_connection",
MatchSubjectAltNames: []SANMatcher{
{Type: "dns", Pattern: `.*\.corp\.example\.com`},
{Type: "email", Pattern: `.*@\.example\.com`},
{Type: "ip_address", Pattern: `192\.168\.0\..*`},
{Type: "uri", Pattern: `spiffe://example.com/department/.*`},
},
}, ""},
}
for i := range cases {
c := &cases[i]
t.Run(c.label, func(t *testing.T) {
err := c.settings.validate()
if c.errorMsg == "" {
assert.NoError(t, err)
} else {
assert.Equal(t, c.errorMsg, err.Error())
}
})
}
}

View file

@ -255,13 +255,16 @@ type Options struct {
DataBrokerStorageCertSkipVerify bool `mapstructure:"databroker_storage_tls_skip_verify" yaml:"databroker_storage_tls_skip_verify,omitempty"`
// ClientCA is the base64-encoded certificate authority to validate client mTLS certificates against.
//
// Deprecated: Use DownstreamMTLS.CA instead.
ClientCA string `mapstructure:"client_ca" yaml:"client_ca,omitempty"`
// ClientCAFile points to a file that contains the certificate authority to validate client mTLS certificates against.
//
// Deprecated: Use DownstreamMTLS.CAFile instead.
ClientCAFile string `mapstructure:"client_ca_file" yaml:"client_ca_file,omitempty"`
// ClientCRL is the base64-encoded certificate revocation list for client mTLS certificates.
ClientCRL string `mapstructure:"client_crl" yaml:"client_crl,omitempty"`
// ClientCRLFile points to a file that contains the certificate revocation list for client mTLS certificates.
ClientCRLFile string `mapstructure:"client_crl_file" yaml:"client_crl_file,omitempty"`
// DownstreamMTLS holds all downstream mTLS settings.
DownstreamMTLS DownstreamMTLSSettings `mapstructure:"downstream_mtls" yaml:"downstream_mtls,omitempty"`
// GoogleCloudServerlessAuthenticationServiceAccount is the service account to use for GCP serverless authentication.
// If unset, the GCP metadata server will be used to query for identity tokens.
@ -371,7 +374,7 @@ func optionsFromViper(configFile string) (*Options, error) {
o := NewDefaultOptions()
v := o.viper
// Load up config
err := bindEnvs(o, v)
err := bindEnvs(v)
if err != nil {
return nil, fmt.Errorf("failed to bind options to env vars: %w", err)
}
@ -506,20 +509,11 @@ func (o *Options) parseHeaders(_ context.Context) error {
return nil
}
// bindEnvs binds a viper instance to each env var of an Options struct based
// on the mapstructure tag
func bindEnvs(o *Options, v *viper.Viper) error {
tagName := `mapstructure`
t := reflect.TypeOf(*o)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
envName := field.Tag.Get(tagName)
err := v.BindEnv(envName)
if err != nil {
return fmt.Errorf("failed to bind field '%s' to env var '%s': %w", field.Name, envName, err)
}
// bindEnvs adds a Viper environment variable binding for each field in the
// Options struct (including nested structs), based on the mapstructure tag.
func bindEnvs(v *viper.Viper) error {
if _, err := bindEnvsRecursive(reflect.TypeOf(Options{}), v, "", ""); err != nil {
return err
}
// Statically bind fields
@ -531,20 +525,56 @@ func bindEnvs(o *Options, v *viper.Viper) error {
if err != nil {
return fmt.Errorf("failed to bind field 'HeadersEnv' to env var 'HEADERS': %w", err)
}
// autocert options
ao := reflect.TypeOf(o.AutocertOptions)
for i := 0; i < ao.NumField(); i++ {
field := ao.Field(i)
envName := field.Tag.Get(tagName)
err := v.BindEnv(envName)
if err != nil {
return fmt.Errorf("failed to bind field '%s' to env var '%s': %w", field.Name, envName, err)
}
}
return nil
}
// bindEnvsRecursive binds all fields of the provided struct type that have a
// "mapstructure" tag to corresponding environment variables, recursively. If a
// nested struct contains no fields with a "mapstructure" tag, a binding will
// be added for the struct itself (e.g. null.Bool).
func bindEnvsRecursive(t reflect.Type, v *viper.Viper, keyPrefix, envPrefix string) (bool, error) {
anyFieldHasMapstructureTag := false
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag, hasTag := field.Tag.Lookup("mapstructure")
if !hasTag || tag == "-" {
continue
}
anyFieldHasMapstructureTag = true
key, _, _ := strings.Cut(tag, ",")
keyPath := keyPrefix + key
envName := envPrefix + strings.ToUpper(key)
if field.Type.Kind() == reflect.Struct {
newKeyPrefix := keyPath
newEnvPrefix := envName
if key != "" {
newKeyPrefix += "."
newEnvPrefix += "_"
}
nestedMapstructure, err := bindEnvsRecursive(field.Type, v, newKeyPrefix, newEnvPrefix)
if err != nil {
return false, err
} else if nestedMapstructure {
// If we've bound any nested fields from this struct, do not
// also bind this struct itself.
continue
}
}
if key != "" {
if err := v.BindEnv(keyPath, envName); err != nil {
return false, fmt.Errorf("failed to bind field '%s' to env var '%s': %w",
field.Name, envName, err)
}
}
}
return anyFieldHasMapstructureTag, nil
}
// Validate ensures the Options fields are valid, and hydrated.
func (o *Options) Validate() error {
ctx := context.TODO()
@ -667,30 +697,22 @@ func (o *Options) Validate() error {
}
if o.ClientCA != "" {
if _, err := base64.StdEncoding.DecodeString(o.ClientCA); err != nil {
return fmt.Errorf("config: bad client ca base64: %w", err)
log.Warn(context.Background()).Msg("config: client_ca is deprecated, set " +
"downstream_mtls.ca instead")
if o.DownstreamMTLS.CA == "" {
o.DownstreamMTLS.CA = o.ClientCA
}
}
if o.ClientCAFile != "" {
_, err := os.ReadFile(o.ClientCAFile)
if err != nil {
return fmt.Errorf("config: bad client ca file: %w", err)
log.Warn(context.Background()).Msg("config: client_ca_file is deprecated, set " +
"downstream_mtls.ca_file instead")
if o.DownstreamMTLS.CAFile == "" {
o.DownstreamMTLS.CAFile = o.ClientCAFile
}
}
if o.ClientCRL != "" {
_, err = cryptutil.CRLFromBase64(o.ClientCRL)
if err != nil {
return fmt.Errorf("config: bad client crl base64: %w", err)
}
}
if o.ClientCRLFile != "" {
_, err = cryptutil.CRLFromFile(o.ClientCRLFile)
if err != nil {
return fmt.Errorf("config: bad client crl file: %w", err)
}
if err := o.DownstreamMTLS.validate(); err != nil {
return fmt.Errorf("config: bad downstream mTLS settings: %w", err)
}
// strip quotes from redirect address (#811)
@ -954,30 +976,6 @@ func (o *Options) GetMetricsBasicAuth() (username, password string, ok bool) {
return string(bs[:idx]), string(bs[idx+1:]), true
}
// GetClientCA returns the client certificate authority. If neither client_ca nor client_ca_file is specified nil will
// be returned.
func (o *Options) GetClientCA() ([]byte, error) {
if o.ClientCA != "" {
return base64.StdEncoding.DecodeString(o.ClientCA)
}
if o.ClientCAFile != "" {
return os.ReadFile(o.ClientCAFile)
}
return nil, nil
}
// GetClientCRL returns the client certificate revocation list bundle. If
// neither client_crl nor client_crl_file is specified nil will be returned.
func (o *Options) GetClientCRL() ([]byte, error) {
if o.ClientCRL != "" {
return base64.StdEncoding.DecodeString(o.ClientCRL)
}
if o.ClientCRLFile != "" {
return os.ReadFile(o.ClientCRLFile)
}
return nil, nil
}
// GetDataBrokerCertificate gets the optional databroker certificate. This method will return nil if no certificate is
// specified.
func (o *Options) GetDataBrokerCertificate() (*tls.Certificate, error) {
@ -1433,7 +1431,7 @@ func (o *Options) ApplySettings(ctx context.Context, certsIndex *cryptutil.Certi
set(&o.DataBrokerStorageType, settings.DatabrokerStorageType)
set(&o.DataBrokerStorageConnectionString, settings.DatabrokerStorageConnectionString)
set(&o.DataBrokerStorageCertSkipVerify, settings.DatabrokerStorageTlsSkipVerify)
set(&o.ClientCA, settings.ClientCa)
o.DownstreamMTLS.applySettingsProto(ctx, settings.DownstreamMtls)
set(&o.GoogleCloudServerlessAuthenticationServiceAccount, settings.GoogleCloudServerlessAuthenticationServiceAccount)
set(&o.UseProxyProtocol, settings.UseProxyProtocol)
set(&o.AutocertOptions.Enable, settings.Autocert)
@ -1450,7 +1448,6 @@ func (o *Options) ApplySettings(ctx context.Context, certsIndex *cryptutil.Certi
setSlice(&o.ProgrammaticRedirectDomainWhitelist, settings.ProgrammaticRedirectDomainWhitelist)
setAuditKey(&o.AuditKey, settings.AuditKey)
setCodecType(&o.CodecType, settings.CodecType)
set(&o.ClientCRL, settings.ClientCrl)
o.BrandingOptions = settings
}

View file

@ -1,6 +1,7 @@
package config
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
@ -11,18 +12,22 @@ import (
"net/url"
"os"
"path/filepath"
"reflect"
"strings"
"sync"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/rs/zerolog"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pomerium/csrf"
"github.com/pomerium/pomerium/internal/identity/oauth/apple"
"github.com/pomerium/pomerium/internal/testutil"
"github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/grpc/config"
)
@ -94,7 +99,7 @@ func Test_bindEnvs(t *testing.T) {
t.Setenv("POMERIUM_DEBUG", "true")
t.Setenv("POLICY", "LSBmcm9tOiBodHRwczovL2h0dHBiaW4ubG9jYWxob3N0LnBvbWVyaXVtLmlvCiAgdG86IAogICAgLSBodHRwOi8vbG9jYWxob3N0OjgwODEsMQo=")
t.Setenv("HEADERS", `{"X-Custom-1":"foo", "X-Custom-2":"bar"}`)
err := bindEnvs(o, v)
err := bindEnvs(v)
if err != nil {
t.Fatalf("failed to bind options to env vars: %s", err)
}
@ -117,6 +122,83 @@ func Test_bindEnvs(t *testing.T) {
}
}
type Foo struct {
FieldOne Bar `mapstructure:"field_one"`
FieldTwo string `mapstructure:"field_two"`
}
type Bar struct {
Baz int `mapstructure:"baz"`
Quux string `mapstructure:"quux"`
}
func Test_bindEnvsRecursive(t *testing.T) {
v := viper.New()
_, err := bindEnvsRecursive(reflect.TypeOf(Foo{}), v, "", "")
require.NoError(t, err)
t.Setenv("FIELD_ONE_BAZ", "123")
t.Setenv("FIELD_ONE_QUUX", "hello")
t.Setenv("FIELD_TWO", "world")
var foo Foo
v.Unmarshal(&foo)
assert.Equal(t, Foo{
FieldOne: Bar{
Baz: 123,
Quux: "hello",
},
FieldTwo: "world",
}, foo)
}
func Test_bindEnvsRecursive_Override(t *testing.T) {
v := viper.New()
v.SetConfigType("yaml")
v.ReadConfig(strings.NewReader(`
field_one:
baz: 10
quux: abc
field_two: hello
`))
// Baseline: values populated from config file.
var foo1 Foo
v.Unmarshal(&foo1)
assert.Equal(t, Foo{
FieldOne: Bar{
Baz: 10,
Quux: "abc",
},
FieldTwo: "hello",
}, foo1)
_, err := bindEnvsRecursive(reflect.TypeOf(Foo{}), v, "", "")
require.NoError(t, err)
// Environment variables should selectively override config file keys.
t.Setenv("FIELD_ONE_QUUX", "def")
var foo2 Foo
v.Unmarshal(&foo2)
assert.Equal(t, Foo{
FieldOne: Bar{
Baz: 10,
Quux: "def",
},
FieldTwo: "hello",
}, foo2)
t.Setenv("FIELD_TWO", "world")
var foo3 Foo
v.Unmarshal(&foo3)
assert.Equal(t, Foo{
FieldOne: Bar{
Baz: 10,
Quux: "def",
},
FieldTwo: "world",
}, foo3)
}
func Test_parseHeaders(t *testing.T) {
// t.Parallel()
tests := []struct {
@ -614,6 +696,48 @@ func TestCompareByteSliceSlice(t *testing.T) {
}
}
func TestDeprecatedClientCAOptions(t *testing.T) {
fakeCACert := []byte("--- FAKE CA CERT ---")
caFile := filepath.Join(t.TempDir(), "CA.pem")
os.WriteFile(caFile, fakeCACert, 0644)
var logOutput bytes.Buffer
zl := zerolog.New(&logOutput)
testutil.SetLogger(t, &zl)
t.Run("CA", func(t *testing.T) {
logOutput.Reset()
o := NewDefaultOptions()
o.AutocertOptions.Enable = true // suppress an unrelated warning
o.ClientCA = "LS0tIEZBS0UgQ0EgQ0VSVCAtLS0="
err := o.Validate()
require.NoError(t, err)
assert.Equal(t, "LS0tIEZBS0UgQ0EgQ0VSVCAtLS0=", o.DownstreamMTLS.CA)
assert.Equal(t, `{"level":"warn","message":"config: client_ca is deprecated, set downstream_mtls.ca instead"}
`,
logOutput.String())
})
t.Run("CAFile", func(t *testing.T) {
logOutput.Reset()
o := NewDefaultOptions()
o.AutocertOptions.Enable = true // suppress an unrelated warning
o.ClientCAFile = caFile
err := o.Validate()
require.NoError(t, err)
assert.Equal(t, caFile, o.DownstreamMTLS.CAFile)
assert.Equal(t, `{"level":"warn","message":"config: client_ca_file is deprecated, set downstream_mtls.ca_file instead"}
`,
logOutput.String())
})
}
func TestOptions_DefaultURL(t *testing.T) {
t.Parallel()

View file

@ -139,10 +139,6 @@ services:
"name": "CERTIFICATE_KEY",
"value": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzhITEJBSXpYa1BlZWcKbGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PLwpFS2dDT0ZGeFVEcW9SODJpWTA2U2FjQWpIbmk2K1BPOXRWUmJGVjB3MTRCREFKU3BCK1Z2V3lsK0ZvUERWL3ZzClozMUZ0WXcrRXdxa2JEeC9rYVQ5dXpmK0xKZGxrZjE0blFRajhFa3kvOGQzbVdKYmIvOXRqT2JzYVFnSjVMTHgKQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUAptcW1rYXdVV3czZWtoajgwU0pnL1RLOVBSYU4vVnZjSTFQZ0FkN0xaenRVUmVTbVR5NWhkOXI2ck9CeHB4d25UCkR2SGtCbjZ2QWdNQkFBRUNnZ0VBQjI4aTBBWVVOU2IxSm5XRmJLenJ1VWN0dTN0Q05Yb3ZKZzZLM0JpUFZNa3EKRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBVwo4ZUplcVJMWkVmc1NTSk9YVEc3UmRHc240cUhGSjAwczJaVGxjSUhTUHduRm0rWGpKaTk5VThHNFhzVW9YbzByCkd5KzBWQ3VVN004Z0lDRUhIc3JRTzlYREQzblQyaml1NVRqckt3anV0M0Vtb0pzc0k1YnF4MzMrT0J1NUJwQ1AKQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVApiTGtMRnlXQk5UV1VaMlIvMnd4bXVvQzZtTFp3ODc5TUxDS012azFkb1FLQmdRRGhtd0dhZkpOeW1UaUVRWlJJClNzUXg0c2VxZk9LZmdGQzdvaHFIOWNST091OElKMW83cTJwTTJXNFhpVitTM3dUZFBHbWNhNklPalgyM2lzVkIKMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzNwpheHpsYU1yeEV1M0xJOVVFN050cmRRaUJ5UUtCZ1FEVmRJNmNlSVZCVDZSZ3ZWR3Q4emtMalBJRmpoUUVIQUlwCnVoaXJncXBTNkNYOUJseWYyK280MHptZmozaGU1ckNjRW9CNU1zZU0rRGdGYmNWaDJlL01WbllpTk53NkpDREIKQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleQp1QkhWQnYvNHR3S0JnSHdIdWVQeTVTVTFzMnFTbXpEN1djMkxQZll1M25DT0hOUnJGR2IyNk11UmZ1UmVyaTdyCjJHOFRnb0VTRnljcDBRVElOOCsxSk0wWFlLeE5jSkQ2QjhWMXdLYmJwUXN5bW5lSTFnanV0aUIvSWd3L1BrREsKQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWgpmTjJZZVlieVljYU0xMXAxVmlsdWxWVFZqWTNpL0ZaaURSNFNML0lHSldqTi9Temc0aVhZc0tGbXUrZHVsT1psCmNCQUxwRUtycXBtelhZdHJONmJzdjE4KzVlTzNxR2JLMkRyRXEzZVdWZXYyS29UTW9ieHo3ZysrWEJJV0ptTEEKSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkUwpLcmx0d21vZEhpcVhOYlZrd2JXMUFGUEpiaVlhaTRZRmZLNElBYmlmL1lteGY5Rzc4YU9rcjlacENJek9rRFBaCllwRXdRR1dzQWhFbENGdmM4RS81ZEhFU1NwK3RXdFArTmx1aW1wRnFpRGczL1NVbk13TzJ4SDBuaExhMHplamgKZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
},
{
"name": "CLIENT_CRL",
"value": "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K"
},
{
"name": "COOKIE_SECRET",
"value": "UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w="
@ -155,6 +151,10 @@ services:
"name": "DATABROKER_STORAGE_TYPE",
"value": "postgres"
},
{
"name": "DOWNSTREAM_MTLS_CRL",
"value": "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K"
},
{
"name": "ENVOY_ADMIN_ADDRESS",
"value": "0.0.0.0:9901"

View file

@ -159,11 +159,11 @@ services:
CERTIFICATE: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVVakNDQXJxZ0F3SUJBZ0lSQUtOYUVxQ21tWmZobWNZZ1p5MDFXQ3N3RFFZSktvWklodmNOQVFFTEJRQXcKZ1lNeEhqQWNCZ05WQkFvVEZXMXJZMlZ5ZENCa1pYWmxiRzl3YldWdWRDQkRRVEVzTUNvR0ExVUVDd3dqWTJGcwpaV0pBWTJGc1pXSXRjR010YkdsdWRYZ2dLRU5oYkdWaUlFUnZlSE5sZVNreE16QXhCZ05WQkFNTUttMXJZMlZ5CmRDQmpZV3hsWWtCallXeGxZaTF3WXkxc2FXNTFlQ0FvUTJGc1pXSWdSRzk0YzJWNUtUQWVGdzB5TVRBNE1UQXgKTnpNeU1UQmFGdzB5TXpFeE1UQXhPRE15TVRCYU1GY3hKekFsQmdOVkJBb1RIbTFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCalpYSjBhV1pwWTJGMFpURXNNQ29HQTFVRUN3d2pZMkZzWldKQVkyRnNaV0l0Y0dNdGJHbHVkWGdnCktFTmhiR1ZpSUVSdmVITmxlU2t3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzgKSExCQUl6WGtQZWVnbGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRAp5VmhEVDBRbEkvTy9FS2dDT0ZGeFVEcW9SODJpWTA2U2FjQWpIbmk2K1BPOXRWUmJGVjB3MTRCREFKU3BCK1Z2Cld5bCtGb1BEVi92c1ozMUZ0WXcrRXdxa2JEeC9rYVQ5dXpmK0xKZGxrZjE0blFRajhFa3kvOGQzbVdKYmIvOXQKak9ic2FRZ0o1TEx4Q1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcQpiWlVERytaaW9BclBtcW1rYXdVV3czZWtoajgwU0pnL1RLOVBSYU4vVnZjSTFQZ0FkN0xaenRVUmVTbVR5NWhkCjlyNnJPQnhweHduVER2SGtCbjZ2QWdNQkFBR2piREJxTUE0R0ExVWREd0VCL3dRRUF3SUZvREFUQmdOVkhTVUUKRERBS0JnZ3JCZ0VGQlFjREFUQWZCZ05WSFNNRUdEQVdnQlNGaGxoWWdFZktUcGxWT2VuZVZHMyszSUUvVFRBaQpCZ05WSFJFRUd6QVpnaGNxTG14dlkyRnNhRzl6ZEM1d2IyMWxjbWwxYlM1cGJ6QU5CZ2txaGtpRzl3MEJBUXNGCkFBT0NBWUVBdWZRQUY3OXM3YzFnbVo5Q0lLQlNHa0hoK1NIMDFDdUtZbm5IaU1vd0hzVGlvRmFVQVFzZC9QNFgKYzJYQnFjMzRlVDNtQ3ZwZ1pqSGJqejZKbG5UWUp4dUx2VnFuVkIzZW10V3JiMWNRdmg4QnBoeHNwVGxTOHVpRQpBRWYvbmd0cHpmQS9mNGxwR2t6clEwY3lQa0VKR3o1MTFxOTdpdHpuOVJaWnpWVFp4TlZGU1AydlZoTk5RVnNXCk94YWtjdllSZ256OEFPUVMzT1BIajJGUWMzaWlic2hjdDVsZUl3WVpGY3hJTkdIUjZLTDYrL0xTZVBOQ0VNbUsKcXltVlBrUUdzSWNVNkdROWZ4YVN1NG1wK0lVQUxQcm9pekVWSThTVms1bk9tM0hJZXorWmZYaHpmbkd4MDZTSQo2TnVvUVFQcVVCZVplWG4yWUZZaGlwZVJkclF4dkEzNi9ZWGEvQWtYQ2VVMHBYeGJ0WEtjdmF0ZnJpNUtuWUpECmtINTlhK2FGa1RzbDQxdGZJMmNuUllWZGRxWFZsM096TGJjZ0FGTG4xV2VDMXh4M3hSWGk3S2xkb2tPbHZndisKQjZuYVdmQ3hSbFdaL2xzbUhhZTRrYzFXSDRLYzduSytJVGI0MEVralY2OC9BN2tyWnNOMVZjcU50cG9tWWtnRQp4alVFOFhVdQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
CERTIFICATE_AUTHORITY: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUxekNDQXorZ0F3SUJBZ0lRWjEzOWNkL3BhUGRrUzJKeUF1N2tFREFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKZ3pFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNU3d3S2dZRFZRUUxEQ05qWVd4bApZa0JqWVd4bFlpMXdZeTFzYVc1MWVDQW9RMkZzWldJZ1JHOTRjMlY1S1RFek1ERUdBMVVFQXd3cWJXdGpaWEowCklHTmhiR1ZpUUdOaGJHVmlMWEJqTFd4cGJuVjRJQ2hEWVd4bFlpQkViM2h6WlhrcE1CNFhEVEl4TURneE1ERTMKTXpJd09Wb1hEVE14TURneE1ERTNNekl3T1Zvd2dZTXhIakFjQmdOVkJBb1RGVzFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCRFFURXNNQ29HQTFVRUN3d2pZMkZzWldKQVkyRnNaV0l0Y0dNdGJHbHVkWGdnS0VOaGJHVmlJRVJ2CmVITmxlU2t4TXpBeEJnTlZCQU1NS20xclkyVnlkQ0JqWVd4bFlrQmpZV3hsWWkxd1l5MXNhVzUxZUNBb1EyRnMKWldJZ1JHOTRjMlY1S1RDQ0FhSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnR1BBRENDQVlvQ2dnR0JBTmJLeU16NQpNVlc2WUtkamgxb0lOMU1uN1BFMnBINVNiSlNwV3hkQUdoZEJrQmtwQWE3T3hhcmpINUtWa0NUU2E3b25jbGE3CnFOdUpaUzZtQm1veEYrUitjUjNqeUdkVUFZbG96bDFqbGZxTElmQy8rZzdWN1ZtT0puOTh0akI0MmZhdHhMbDYKV1BBdzFKRE5zV3RRZmhLaGJjSHV0N1JzRjByTU9PSGN3eXdUUjdMT3lDbUllbDFwY21wVjRoYlZjVDZlVndvUApIWHlKU2E5Y3FhTVE1WHJkb2dhaTRJcVpaSUdMSGVMc1RWdXRPZ0pGWEVldmxYL1FUM3NXb21FY3R6aDM4SnM0CjlEaUFQRDZkNFk3L0NQTFlFZmsyOUpROU5aaHBnRHNpOWh1NUZISFpjWHdmMUlIbHcvQ0JWZ242aitqbXZLS3oKOTBNYTFvcXV2M1c2ZHR0aWQveENjTEd1MlMrOTZUenJ5a21veTVWYWNMdFZFUDQxWW1vVmxzOTFybG83b2xwZQpRV0Zibm1jbzczOVRJLzRoK0hvZG9scGVyUUVSUWw3dUNucEtWUFozV29rS3VSaDVwa3FrUXAvYXJRanR3Y1J0Ckc0M0NyRHBibCt1U2pNQ0F4aGE5NThlVFl2dG9qVE1udkx0c0dJRDFoR1hucWx3KzVLaktyZ1JIclFJREFRQUIKbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQWdRd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQWRCZ05WSFE0RQpGZ1FVaFlaWVdJQkh5azZaVlRucDNsUnQvdHlCUDAwd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFBMUYvYXByCmw2cE5UM01wL014aFVVZ282dXNFSkNyeUdRY0xSZmV4eVFYR04zaHVDbUlyUDU1VkZhOEVUUEF0anNyNlBNZTcKN3Z2RWo4ZUZ1Mkp0S292bFF3TmV3WVU5Y2pBTUNWYUZpTmJyUWEyMGh6aFdjMmpzNmR5aWxkRTYvRFB6YmVkcwpLREF4aEZOcDM1U2x3dFJ0S2sxU3p4SnhzcVN3amZ4SThmcCtSLzB3TzhnMGZXVGRNMmdDcFJ3WU1Od0pFTEVnCitkU2x2SkN3dXUrcnp4TGFsemFQRjFQTVRXNzJPRUxhbC9qNXNEKzJWeXRRNGsrSFVEYnl0MkRuUVQ3WVEzem8KcTAyeDJ1MnNtMVdXL28vdWg4cGpQeGtHUXFMMm1yeVpzNlZIOVZDVTNRa0tORHNzTmQ3MWxyM3dQb0U0WVJIZQpVdnpEMWVEZWVsekJVRk5JcERDamRDc0w1NXlJUHFVc3I2bG1qcEJQTDB2ZWEzM1FUTWJjc1N4dTB1bUdYRGJVCjY2anVVNFoxak9FMHdDbEl2YU82OTlKK0UyZ0JlMWpVTjZBdDZiOEJTb1pxQ3FYWW9ESEdlaTlSQlVkdmdxdG8Ka1Zzb0pmREkvVEZNZWtZZ3BMNVVWWW1MZGZncUxQUFJQOXBRQkxEeDNtc3plQXFudmZUSUNBemZYZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
CERTIFICATE_KEY: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzhITEJBSXpYa1BlZWcKbGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PLwpFS2dDT0ZGeFVEcW9SODJpWTA2U2FjQWpIbmk2K1BPOXRWUmJGVjB3MTRCREFKU3BCK1Z2V3lsK0ZvUERWL3ZzClozMUZ0WXcrRXdxa2JEeC9rYVQ5dXpmK0xKZGxrZjE0blFRajhFa3kvOGQzbVdKYmIvOXRqT2JzYVFnSjVMTHgKQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUAptcW1rYXdVV3czZWtoajgwU0pnL1RLOVBSYU4vVnZjSTFQZ0FkN0xaenRVUmVTbVR5NWhkOXI2ck9CeHB4d25UCkR2SGtCbjZ2QWdNQkFBRUNnZ0VBQjI4aTBBWVVOU2IxSm5XRmJLenJ1VWN0dTN0Q05Yb3ZKZzZLM0JpUFZNa3EKRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBVwo4ZUplcVJMWkVmc1NTSk9YVEc3UmRHc240cUhGSjAwczJaVGxjSUhTUHduRm0rWGpKaTk5VThHNFhzVW9YbzByCkd5KzBWQ3VVN004Z0lDRUhIc3JRTzlYREQzblQyaml1NVRqckt3anV0M0Vtb0pzc0k1YnF4MzMrT0J1NUJwQ1AKQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVApiTGtMRnlXQk5UV1VaMlIvMnd4bXVvQzZtTFp3ODc5TUxDS012azFkb1FLQmdRRGhtd0dhZkpOeW1UaUVRWlJJClNzUXg0c2VxZk9LZmdGQzdvaHFIOWNST091OElKMW83cTJwTTJXNFhpVitTM3dUZFBHbWNhNklPalgyM2lzVkIKMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzNwpheHpsYU1yeEV1M0xJOVVFN050cmRRaUJ5UUtCZ1FEVmRJNmNlSVZCVDZSZ3ZWR3Q4emtMalBJRmpoUUVIQUlwCnVoaXJncXBTNkNYOUJseWYyK280MHptZmozaGU1ckNjRW9CNU1zZU0rRGdGYmNWaDJlL01WbllpTk53NkpDREIKQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleQp1QkhWQnYvNHR3S0JnSHdIdWVQeTVTVTFzMnFTbXpEN1djMkxQZll1M25DT0hOUnJGR2IyNk11UmZ1UmVyaTdyCjJHOFRnb0VTRnljcDBRVElOOCsxSk0wWFlLeE5jSkQ2QjhWMXdLYmJwUXN5bW5lSTFnanV0aUIvSWd3L1BrREsKQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWgpmTjJZZVlieVljYU0xMXAxVmlsdWxWVFZqWTNpL0ZaaURSNFNML0lHSldqTi9Temc0aVhZc0tGbXUrZHVsT1psCmNCQUxwRUtycXBtelhZdHJONmJzdjE4KzVlTzNxR2JLMkRyRXEzZVdWZXYyS29UTW9ieHo3ZysrWEJJV0ptTEEKSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkUwpLcmx0d21vZEhpcVhOYlZrd2JXMUFGUEpiaVlhaTRZRmZLNElBYmlmL1lteGY5Rzc4YU9rcjlacENJek9rRFBaCllwRXdRR1dzQWhFbENGdmM4RS81ZEhFU1NwK3RXdFArTmx1aW1wRnFpRGczL1NVbk13TzJ4SDBuaExhMHplamgKZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
CLIENT_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
COOKIE_SECRET: UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=
DATABROKER_SERVICE_URL: https://pomerium-databroker:5443
DATABROKER_STORAGE_CONNECTION_STRING: postgres://pomerium:password@postgres:5432/test
DATABROKER_STORAGE_TYPE: postgres
DOWNSTREAM_MTLS_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
ENVOY_ADMIN_ADDRESS: 0.0.0.0:9901
GOOGLE_CLOUD_SERVERLESS_AUTHENTICATION_SERVICE_ACCOUNT: ewoiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImF1dGhfdXJpIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImNsaWVudF9lbWFpbCI6ICJyZWRhY3RlZEBwb21lcml1bS1yZWRhY3RlZC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsCiJjbGllbnRfaWQiOiAiMTAxMjE1OTkwNDU4MDAwMzM0Mzg3IiwKImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVktLS0tLVxuTUlJRXZRSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2N3Z2dTakFnRUFBb0lCQVFDOEhMQkFJelhrUGVlZ1xubGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PL1xuRUtnQ09GRnhVRHFvUjgyaVkwNlNhY0FqSG5pNitQTzl0VlJiRlYwdzE0QkRBSlNwQitWdld5bCtGb1BEVi92c1xuWjMxRnRZdytFd3FrYkR4L2thVDl1emYrTEpkbGtmMTRuUVFqOEVreS84ZDNtV0piYi85dGpPYnNhUWdKNUxMeFxuQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUFxubXFta2F3VVd3M2VraGo4MFNKZy9USzlQUmFOL1Z2Y0kxUGdBZDdMWnp0VVJlU21UeTVoZDlyNnJPQnhweHduVFxuRHZIa0JuNnZBZ01CQUFFQ2dnRUFCMjhpMEFZVU5TYjFKbldGYkt6cnVVY3R1M3RDTlhvdkpnNkszQmlQVk1rcVxuRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBV1xuOGVKZXFSTFpFZnNTU0pPWFRHN1JkR3NuNHFIRkowMHMyWlRsY0lIU1B3bkZtK1hqSmk5OVU4RzRYc1VvWG8wclxuR3krMFZDdVU3TThnSUNFSEhzclFPOVhERDNuVDJqaXU1VGpyS3dqdXQzRW1vSnNzSTVicXgzMytPQnU1QnBDUFxuQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVFxuYkxrTEZ5V0JOVFdVWjJSLzJ3eG11b0M2bUxadzg3OU1MQ0tNdmsxZG9RS0JnUURobXdHYWZKTnltVGlFUVpSSVxuU3NReDRzZXFmT0tmZ0ZDN29ocUg5Y1JPT3U4SUoxbzdxMnBNMlc0WGlWK1Mzd1RkUEdtY2E2SU9qWDIzaXNWQlxuMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzN1xuYXh6bGFNcnhFdTNMSTlVRTdOdHJkUWlCeVFLQmdRRFZkSTZjZUlWQlQ2Umd2Vkd0OHprTGpQSUZqaFFFSEFJcFxudWhpcmdxcFM2Q1g5Qmx5ZjIrbzQwem1majNoZTVyQ2NFb0I1TXNlTStEZ0ZiY1ZoMmUvTVZuWWlOTnc2SkNEQlxuQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleVxudUJIVkJ2LzR0d0tCZ0h3SHVlUHk1U1UxczJxU216RDdXYzJMUGZZdTNuQ09ITlJyRkdiMjZNdVJmdVJlcmk3clxuMkc4VGdvRVNGeWNwMFFUSU44KzFKTTBYWUt4TmNKRDZCOFYxd0tiYnBRc3ltbmVJMWdqdXRpQi9JZ3cvUGtES1xuQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWlxuZk4yWWVZYnlZY2FNMTFwMVZpbHVsVlRWalkzaS9GWmlEUjRTTC9JR0pXak4vU3pnNGlYWXNLRm11K2R1bE9abFxuY0JBTHBFS3JxcG16WFl0ck42YnN2MTgrNWVPM3FHYksyRHJFcTNlV1ZldjJLb1RNb2J4ejdnKytYQklXSm1MQVxuSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkU1xuS3JsdHdtb2RIaXFYTmJWa3diVzFBRlBKYmlZYWk0WUZmSzRJQWJpZi9ZbXhmOUc3OGFPa3I5WnBDSXpPa0RQWlxuWXBFd1FHV3NBaEVsQ0Z2YzhFLzVkSEVTU3ArdFd0UCtObHVpbXBGcWlEZzMvU1VuTXdPMnhIMG5oTGEwemVqaFxuZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9XG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4iLAoicHJpdmF0ZV9rZXlfaWQiOiAiZTA3ZjdjOTM4NzBjN2UwM2Y4ODM1NjBlY2Q4ZmQwZjRkMjdiMDA4MSIsCiJwcm9qZWN0X2lkIjogInBvbWVyaXVtLXJlZGFjdGVkIiwKInRva2VuX3VyaSI6ICJodHRwOi8vbW9jay1pZHA6ODAyNC90b2tlbiIsCiJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIKfQ==
GRPC_ADDRESS: :5443
@ -219,11 +219,11 @@ services:
CERTIFICATE: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVYekNDQXNlZ0F3SUJBZ0lSQU5NalQzSmp2cEdtbjRUTzVPWUFyazh3RFFZSktvWklodmNOQVFFTEJRQXcKZ1lNeEhqQWNCZ05WQkFvVEZXMXJZMlZ5ZENCa1pYWmxiRzl3YldWdWRDQkRRVEVzTUNvR0ExVUVDd3dqWTJGcwpaV0pBWTJGc1pXSXRjR010YkdsdWRYZ2dLRU5oYkdWaUlFUnZlSE5sZVNreE16QXhCZ05WQkFNTUttMXJZMlZ5CmRDQmpZV3hsWWtCallXeGxZaTF3WXkxc2FXNTFlQ0FvUTJGc1pXSWdSRzk0YzJWNUtUQWVGdzB4T1RBMk1ERXcKTURBd01EQmFGdzB6TVRFeE1UVXhPVEV4TlRWYU1Gc3hKekFsQmdOVkJBb1RIbTFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCalpYSjBhV1pwWTJGMFpURXdNQzRHQTFVRUN3d25ZMkZzWldKQVkyRnNaV0l0YkdGd2RHOXdMV3hwCmJuVjRJQ2hEWVd4bFlpQkViM2h6WlhrcE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0MKQVFFQTlqUkR2Mkl5V1FaV3V1STkxdWdlbWF3R0RxK1BERUpUaVNDZ3ZhWWkwSEc0SEowNndwVjk4cDNTYWZVbgpwWU12ajlmY3lqbkJaOHlvcGU5VUQrakFSMVhEYmI1YlUvVU1iV3JkU29LWVM4a0dzYllDdDAzMHk4QWRaejY5CmI3Q2t2Y25IQUpPcDV4VXRYU1ExaEo3ZjQzZ29aaEdSbHJKU2cxSkpWKzJTTlUxMHNnM1V3YjNieGdBL1hrRk0KaUIzWnF2STRJNTh3RzBqakxVSEFmQ043eTFEQWFiVlNJQll6b1B5cjJxUUEvR0lHMWJsbzljWWdrRFlkb1d3UgpwZ21maHBLQ2NrNUxWZWdZejNBcSs4NkpPVGxHbWc5WlIxaUdNSEpNYklsUGJNdEU2MXovQjhtWUc5aUptUHJTCmYzNHVZVlJ4VDZTMkZWTkU1cDZVbHZXNHd3SURBUUFCbzNVd2N6QU9CZ05WSFE4QkFmOEVCQU1DQmFBd0V3WUQKVlIwbEJBd3dDZ1lJS3dZQkJRVUhBd0V3REFZRFZSMFRBUUgvQkFJd0FEQWZCZ05WSFNNRUdEQVdnQlNGaGxoWQpnRWZLVHBsVk9lbmVWRzMrM0lFL1RUQWRCZ05WSFJFRUZqQVVnaEp3YjIxbGNtbDFiUzFoZFhSb2IzSnBlbVV3CkRRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFESHNQT1p6WHh5eWMrZ1EwYkxSbG5WejNZMDV6cTNmV2gxeWp0U04KMmtQTFJ1aU02ZkZWUGlDV1VuUzk0cnNDeDV6Sk0xQnRNR3VNcUNMWGxmZERWYlZNcDM2d0NHMms5TWt3aE01dgpuTFRXTkkzclFZSUJnU0xvdFNTeTZYdUV5U1pJQlhUZ2RHODFYcG5pVjBUc1dKMjJEdGxlMlhOZUo1cHNnMS93CjdMbTZLdElkL3FEYUF5T1pLR1Y2Z21GL0YyNTB4RDkxYys3Mk9DUkFrK0x2WXhydFBVY3lwV0lNV2lMUEtlRkMKQnB6Q3BsNDB3c0o5YzVFMTdJcWNjMVVzanRwUnVXSlFRb0FBb3NhQ2RVUThXN04yMXdyNTcyTjFKcmNVOElBeAprN3U3T0Rrc24vK0NaODQ2N3dYclB5OXZGL3F2QkxtYWVFMWswd3VnTldlSnZNT0JLcGRKNG5iS0VCbU5xcmpMCmRRM21aTW90ZWNlelRDY29WYmRhdC9NVHNKR3hPSG42ZExoeHlKQzQ5K0FxbjJ2OGJ1ajZEbk56M3d3VHZxdXUKOGJEOW83SzlHdmRaaEtBNUxISmpFOXNkdmxzZVpNUnZqUGVnUDRWeWpaWmlBejBFUW04d292MHYvK2J5d2RUZgp5QjQ4eVJjSVdzdzZyU3BNdHR5ZU1neGJiQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
CERTIFICATE_AUTHORITY: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUxekNDQXorZ0F3SUJBZ0lRWjEzOWNkL3BhUGRrUzJKeUF1N2tFREFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKZ3pFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNU3d3S2dZRFZRUUxEQ05qWVd4bApZa0JqWVd4bFlpMXdZeTFzYVc1MWVDQW9RMkZzWldJZ1JHOTRjMlY1S1RFek1ERUdBMVVFQXd3cWJXdGpaWEowCklHTmhiR1ZpUUdOaGJHVmlMWEJqTFd4cGJuVjRJQ2hEWVd4bFlpQkViM2h6WlhrcE1CNFhEVEl4TURneE1ERTMKTXpJd09Wb1hEVE14TURneE1ERTNNekl3T1Zvd2dZTXhIakFjQmdOVkJBb1RGVzFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCRFFURXNNQ29HQTFVRUN3d2pZMkZzWldKQVkyRnNaV0l0Y0dNdGJHbHVkWGdnS0VOaGJHVmlJRVJ2CmVITmxlU2t4TXpBeEJnTlZCQU1NS20xclkyVnlkQ0JqWVd4bFlrQmpZV3hsWWkxd1l5MXNhVzUxZUNBb1EyRnMKWldJZ1JHOTRjMlY1S1RDQ0FhSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnR1BBRENDQVlvQ2dnR0JBTmJLeU16NQpNVlc2WUtkamgxb0lOMU1uN1BFMnBINVNiSlNwV3hkQUdoZEJrQmtwQWE3T3hhcmpINUtWa0NUU2E3b25jbGE3CnFOdUpaUzZtQm1veEYrUitjUjNqeUdkVUFZbG96bDFqbGZxTElmQy8rZzdWN1ZtT0puOTh0akI0MmZhdHhMbDYKV1BBdzFKRE5zV3RRZmhLaGJjSHV0N1JzRjByTU9PSGN3eXdUUjdMT3lDbUllbDFwY21wVjRoYlZjVDZlVndvUApIWHlKU2E5Y3FhTVE1WHJkb2dhaTRJcVpaSUdMSGVMc1RWdXRPZ0pGWEVldmxYL1FUM3NXb21FY3R6aDM4SnM0CjlEaUFQRDZkNFk3L0NQTFlFZmsyOUpROU5aaHBnRHNpOWh1NUZISFpjWHdmMUlIbHcvQ0JWZ242aitqbXZLS3oKOTBNYTFvcXV2M1c2ZHR0aWQveENjTEd1MlMrOTZUenJ5a21veTVWYWNMdFZFUDQxWW1vVmxzOTFybG83b2xwZQpRV0Zibm1jbzczOVRJLzRoK0hvZG9scGVyUUVSUWw3dUNucEtWUFozV29rS3VSaDVwa3FrUXAvYXJRanR3Y1J0Ckc0M0NyRHBibCt1U2pNQ0F4aGE5NThlVFl2dG9qVE1udkx0c0dJRDFoR1hucWx3KzVLaktyZ1JIclFJREFRQUIKbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQWdRd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQWRCZ05WSFE0RQpGZ1FVaFlaWVdJQkh5azZaVlRucDNsUnQvdHlCUDAwd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFBMUYvYXByCmw2cE5UM01wL014aFVVZ282dXNFSkNyeUdRY0xSZmV4eVFYR04zaHVDbUlyUDU1VkZhOEVUUEF0anNyNlBNZTcKN3Z2RWo4ZUZ1Mkp0S292bFF3TmV3WVU5Y2pBTUNWYUZpTmJyUWEyMGh6aFdjMmpzNmR5aWxkRTYvRFB6YmVkcwpLREF4aEZOcDM1U2x3dFJ0S2sxU3p4SnhzcVN3amZ4SThmcCtSLzB3TzhnMGZXVGRNMmdDcFJ3WU1Od0pFTEVnCitkU2x2SkN3dXUrcnp4TGFsemFQRjFQTVRXNzJPRUxhbC9qNXNEKzJWeXRRNGsrSFVEYnl0MkRuUVQ3WVEzem8KcTAyeDJ1MnNtMVdXL28vdWg4cGpQeGtHUXFMMm1yeVpzNlZIOVZDVTNRa0tORHNzTmQ3MWxyM3dQb0U0WVJIZQpVdnpEMWVEZWVsekJVRk5JcERDamRDc0w1NXlJUHFVc3I2bG1qcEJQTDB2ZWEzM1FUTWJjc1N4dTB1bUdYRGJVCjY2anVVNFoxak9FMHdDbEl2YU82OTlKK0UyZ0JlMWpVTjZBdDZiOEJTb1pxQ3FYWW9ESEdlaTlSQlVkdmdxdG8Ka1Zzb0pmREkvVEZNZWtZZ3BMNVVWWW1MZGZncUxQUFJQOXBRQkxEeDNtc3plQXFudmZUSUNBemZYZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
CERTIFICATE_KEY: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRRDJORU8vWWpKWkJsYTYKNGozVzZCNlpyQVlPcjQ4TVFsT0pJS0M5cGlMUWNiZ2NuVHJDbFgzeW5kSnA5U2VsZ3krUDE5ektPY0ZuektpbAo3MVFQNk1CSFZjTnR2bHRUOVF4dGF0MUtncGhMeVFheHRnSzNUZlRMd0IxblByMXZzS1M5eWNjQWs2bm5GUzFkCkpEV0VudC9qZUNobUVaR1dzbEtEVWtsWDdaSTFUWFN5RGRUQnZkdkdBRDllUVV5SUhkbXE4amdqbnpBYlNPTXQKUWNCOEkzdkxVTUJwdFZJZ0ZqT2cvS3ZhcEFEOFlnYlZ1V2oxeGlDUU5oMmhiQkdtQ1orR2tvSnlUa3RWNkJqUApjQ3I3em9rNU9VYWFEMWxIV0lZd2NreHNpVTlzeTBUclhQOEh5WmdiMkltWSt0Si9maTVoVkhGUHBMWVZVMFRtCm5wU1c5YmpEQWdNQkFBRUNnZ0VBWk9ML3krSEtMYzY2SlhSbDBMVm5MS05nREE2R2VJaUpRSXk5TVZsdHRLcVUKdml6emtoNjk4SGdaYTgvSWdqc2lkemdHUWx1dVZBRjZMaHpHL29ucW1KQ2ROMUFramwvQXl1bGFhcGpmSFZidgp4a3lHQ21VSVphR0Fxdmo3bVZQeC9jODhHNUZtc3NscndGb0JFQ29tSmtqcmpQK3YvK2RzaG1GbXFvQXdSR1IrCkp0ZW1xTlo3QWNwajhzV09ZeWQxZDlLbWtxS1RlaFZTSmpUaExlNjhvWXpxV3JxZWtVY2psbkI0a2ppbEU5VzAKYm15N0JqQlJqTlRGTWtSRUQ0eWtWUXlscGVZd1JXQkhYdzUxMlVVQVYxQnEyb0k0TGJoc0xYR1U2YXZSKy9XagpoemhKQ3ZpUTlxSUJ1OVhsRWtkcjdrQjVOQVVOd25pZUJhRE1VZmpxd1FLQmdRRDVrV3RtWmk0T3U4T1Z3QjF5CkZraE93T3RyM1oyTjBTOVZJbjAwc3ROTVlUVGNxT0J1Ynl2Y3RPdzA4UDJDVTVRcUtxRzY5QUtPRlBubm0vOEkKR1Vvc2k1eEh3S2Q3MTdoN1VhK0VTdG9GNkRDemZhR1BadXkrN0JnVFloeS96cjA5L0VJYkRPZHBOZEpmbis2ago1K0lDSjVqdEJRMUVUZXRJRTVQbWZVMXRvUUtCZ1FEOGpLYXYrZGRIUmwvMGZGN1plWit5TnZheGlCWGhXZkh2ClVXZVVaOXlKK04vbXhOckpqYTkzam5aZzFCTnIrdlYxUzNXTEwwN01wZm9HZ0IzWW82K3hXSlVhamRreTJMdE0KeGwxU1VmSERBRmQ1bWpGWVNTM3IvUGJxNDdJQ2hFK0ZmYndWNk9PNlpkYW1US3Y0TjFncUpvZWl0d2hvcEVGeApPYjBybm9DajR3S0JnQVB6NTYyUmhMMDdBQmdKR081THFBMkhSTE5LcVVvcnZBSXZMNmg4QkppN0dXazlTNEMwClJnK1MxZ0xvcGp0QU02S1BWa3h0dlBTZkpHNGtyRjltZHlSSmVjb3hKUFh6THJyVlNtQmdCeC84MDNpa1RzREUKc284N2tnNE1pY1FIOUR0ZEdYYndOMklWTmlYSmxMQUg1aTUramcrQyt2alAreUFESDE2Uk1YN0JBb0dCQU80WQpSRVgveTMvOHp4WVY4dTRoQmZma2JhdHQyd0w3NDJWMlg2ckFTR0VqYXlPTFQ2RlpuS1dnZitaRnlwR3dwWjBSCnFSMnhXaDhDRTdmeExUSkRENjZwRHRsY0Jmc3o3VkV5YW1UanNJUGhYSmJlVWNza0l0RXJTamFrdC93N2RTVXIKSnhtWTJLbXd2UzlIZFpHcnk4amhUbHFQS0xST3R3dmlIWUIwREY5MUFvR0FkeDJ3TGllTzVUcThBdkZhOXVydApCaVhwVFlMQ2JaWVBGZkVYTmZCYkt2NmFiWExBd2ZyRkQ1dkdrM0pFY2JqUTlnbWN6YW53QTFkUVhmN1NJLzRwCkZrUWhaSjhhdGJEaWl3SEVaeHpUeSt3cGx6OVlSN2tNQ0hkMndacXBsRCt1eXVxRWtZVVE5R09YZ2IzSUthVk4KVmd4QnJWSzlCNjdXM3FQZVRYMWxJdFU9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
CLIENT_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
COOKIE_SECRET: UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=
DATABROKER_SERVICE_URL: https://pomerium-databroker:5443
DATABROKER_STORAGE_CONNECTION_STRING: postgres://pomerium:password@postgres:5432/test
DATABROKER_STORAGE_TYPE: postgres
DOWNSTREAM_MTLS_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
ENVOY_ADMIN_ADDRESS: 0.0.0.0:9901
GOOGLE_CLOUD_SERVERLESS_AUTHENTICATION_SERVICE_ACCOUNT: ewoiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImF1dGhfdXJpIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImNsaWVudF9lbWFpbCI6ICJyZWRhY3RlZEBwb21lcml1bS1yZWRhY3RlZC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsCiJjbGllbnRfaWQiOiAiMTAxMjE1OTkwNDU4MDAwMzM0Mzg3IiwKImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVktLS0tLVxuTUlJRXZRSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2N3Z2dTakFnRUFBb0lCQVFDOEhMQkFJelhrUGVlZ1xubGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PL1xuRUtnQ09GRnhVRHFvUjgyaVkwNlNhY0FqSG5pNitQTzl0VlJiRlYwdzE0QkRBSlNwQitWdld5bCtGb1BEVi92c1xuWjMxRnRZdytFd3FrYkR4L2thVDl1emYrTEpkbGtmMTRuUVFqOEVreS84ZDNtV0piYi85dGpPYnNhUWdKNUxMeFxuQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUFxubXFta2F3VVd3M2VraGo4MFNKZy9USzlQUmFOL1Z2Y0kxUGdBZDdMWnp0VVJlU21UeTVoZDlyNnJPQnhweHduVFxuRHZIa0JuNnZBZ01CQUFFQ2dnRUFCMjhpMEFZVU5TYjFKbldGYkt6cnVVY3R1M3RDTlhvdkpnNkszQmlQVk1rcVxuRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBV1xuOGVKZXFSTFpFZnNTU0pPWFRHN1JkR3NuNHFIRkowMHMyWlRsY0lIU1B3bkZtK1hqSmk5OVU4RzRYc1VvWG8wclxuR3krMFZDdVU3TThnSUNFSEhzclFPOVhERDNuVDJqaXU1VGpyS3dqdXQzRW1vSnNzSTVicXgzMytPQnU1QnBDUFxuQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVFxuYkxrTEZ5V0JOVFdVWjJSLzJ3eG11b0M2bUxadzg3OU1MQ0tNdmsxZG9RS0JnUURobXdHYWZKTnltVGlFUVpSSVxuU3NReDRzZXFmT0tmZ0ZDN29ocUg5Y1JPT3U4SUoxbzdxMnBNMlc0WGlWK1Mzd1RkUEdtY2E2SU9qWDIzaXNWQlxuMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzN1xuYXh6bGFNcnhFdTNMSTlVRTdOdHJkUWlCeVFLQmdRRFZkSTZjZUlWQlQ2Umd2Vkd0OHprTGpQSUZqaFFFSEFJcFxudWhpcmdxcFM2Q1g5Qmx5ZjIrbzQwem1majNoZTVyQ2NFb0I1TXNlTStEZ0ZiY1ZoMmUvTVZuWWlOTnc2SkNEQlxuQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleVxudUJIVkJ2LzR0d0tCZ0h3SHVlUHk1U1UxczJxU216RDdXYzJMUGZZdTNuQ09ITlJyRkdiMjZNdVJmdVJlcmk3clxuMkc4VGdvRVNGeWNwMFFUSU44KzFKTTBYWUt4TmNKRDZCOFYxd0tiYnBRc3ltbmVJMWdqdXRpQi9JZ3cvUGtES1xuQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWlxuZk4yWWVZYnlZY2FNMTFwMVZpbHVsVlRWalkzaS9GWmlEUjRTTC9JR0pXak4vU3pnNGlYWXNLRm11K2R1bE9abFxuY0JBTHBFS3JxcG16WFl0ck42YnN2MTgrNWVPM3FHYksyRHJFcTNlV1ZldjJLb1RNb2J4ejdnKytYQklXSm1MQVxuSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkU1xuS3JsdHdtb2RIaXFYTmJWa3diVzFBRlBKYmlZYWk0WUZmSzRJQWJpZi9ZbXhmOUc3OGFPa3I5WnBDSXpPa0RQWlxuWXBFd1FHV3NBaEVsQ0Z2YzhFLzVkSEVTU3ArdFd0UCtObHVpbXBGcWlEZzMvU1VuTXdPMnhIMG5oTGEwemVqaFxuZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9XG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4iLAoicHJpdmF0ZV9rZXlfaWQiOiAiZTA3ZjdjOTM4NzBjN2UwM2Y4ODM1NjBlY2Q4ZmQwZjRkMjdiMDA4MSIsCiJwcm9qZWN0X2lkIjogInBvbWVyaXVtLXJlZGFjdGVkIiwKInRva2VuX3VyaSI6ICJodHRwOi8vbW9jay1pZHA6ODAyNC90b2tlbiIsCiJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIKfQ==
GRPC_ADDRESS: :5443
@ -278,11 +278,11 @@ services:
CERTIFICATE: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVYekNDQXNlZ0F3SUJBZ0lRWDBCTFVEUmE0cHI3TFlueGRkYzRKREFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKZ3pFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNU3d3S2dZRFZRUUxEQ05qWVd4bApZa0JqWVd4bFlpMXdZeTFzYVc1MWVDQW9RMkZzWldJZ1JHOTRjMlY1S1RFek1ERUdBMVVFQXd3cWJXdGpaWEowCklHTmhiR1ZpUUdOaGJHVmlMWEJqTFd4cGJuVjRJQ2hEWVd4bFlpQkViM2h6WlhrcE1CNFhEVEU1TURZd01UQXcKTURBd01Gb1hEVE14TVRFeE5URTVNVEl5TjFvd1d6RW5NQ1VHQTFVRUNoTWViV3RqWlhKMElHUmxkbVZzYjNCdApaVzUwSUdObGNuUnBabWxqWVhSbE1UQXdMZ1lEVlFRTERDZGpZV3hsWWtCallXeGxZaTFzWVhCMGIzQXRiR2x1CmRYZ2dLRU5oYkdWaUlFUnZlSE5sZVNrd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUIKQVFEYVhWcVp4MXNXLzREdTlBdTJnSjNsT2JubVlzQzhpV2JLSTJ4UWVrSWljc0NHMm5qYkVPejMza2FuL3VsaQpNbXh2TEF2UUcwTjhDU3djSzlhakFydHJvbE96S2NZajFmUzNmK25yRWZpa3NiemNHNFFiMDc0MUtlcTJLZFJkCllwR0E0TSs2Y0c0QTQvVnhDOWxnNU5UMDJXd2tYUlRUVWVjUWJIdTV5blEzcjR1MWk3R3RCb3RDODRQVGlFdXUKUVpEbFcxMUx2UjlTUW5ZenVZUmM0aG9QR1pKN1dBNE1jdlIxY3MyUHZWU3FOWjc4aGZDRGgyQ21mYUxGQVhxVgpSUk5sbUVlclMvWjQ1N3JnbHhrOTlKSlBrd1FTWm43KzBrcHJKMm9ubmRtUFpxN2JnT1FOdG13WFQ0cTRjSEFCCjFyTWRGTEdXODJqMGFnbmhMdXl4MEtuTkFnTUJBQUdqZGpCME1BNEdBMVVkRHdFQi93UUVBd0lGb0RBVEJnTlYKSFNVRUREQUtCZ2dyQmdFRkJRY0RBVEFNQmdOVkhSTUJBZjhFQWpBQU1COEdBMVVkSXdRWU1CYUFGSVdHV0ZpQQpSOHBPbVZVNTZkNVViZjdjZ1Q5Tk1CNEdBMVVkRVFRWE1CV0NFM0J2YldWeWFYVnRMV1JoZEdGaWNtOXJaWEl3CkRRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFGSkovQzVRT3hBRnFxMXRjZDN5REdPbzB6V29NejBzZDZEZnQ1cVAKTXRaOWx5WTU4dnpZN1pIWEVwVzU2Mm9hYmpuRmRTMVYyZTFtTFM5ZGRFQkZIdzRxQm1hZmZHcFVQdzZkTndXawpCSmJVRUhXVFhvVmRaejhYMUExei9mUkNEY0NxRW50amZkUXo3NFkrZFZZcDhzQ215UmVIdy8rQ2tCMmtNblRZCmticzJBMUxpYnZ4ZUlrOVRmN0k0THZFbjNSRXZ1bjZjcSs4R1gvN1QxTm1KUS9sSkZjS0hrSXpvZFVBUTR4TUcKL29xUXFFalhHalM1cTRKMGNjVExDMlQ1Y0VsSDlHdnFwV3Q1L3RJSi96aTlFajl2UVROZVJ4Nllsc2RGNXA4OQpmbm9EWkZUb3BteXF3MGdySk5EN25mNU93R3BTNzlwN1NFcmUvWi9QTmlTSmdWNlU0L21IY25PVXk2UVk0SjBjClhqd2laK1J6cjlRam5DS2xPMEprNDI1U0J2Q0M2L0ZDcHViQ1JpSjViR0Rkd1k3bE9ydmNRV3R2NDJ1WUp4UEEKeG0yM0Q2WWowdjQrVWhNMWwvVURGdjlFcGgwSXdGM1I5Sk5WOGYvZUszM0VDc2QyQW5PWDkrTVljMG0weHRJMwpVMUYwM3czTlR5c2hKYXQ0ZHp4QytBbTBaZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
CERTIFICATE_AUTHORITY: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUxekNDQXorZ0F3SUJBZ0lRWjEzOWNkL3BhUGRrUzJKeUF1N2tFREFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKZ3pFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNU3d3S2dZRFZRUUxEQ05qWVd4bApZa0JqWVd4bFlpMXdZeTFzYVc1MWVDQW9RMkZzWldJZ1JHOTRjMlY1S1RFek1ERUdBMVVFQXd3cWJXdGpaWEowCklHTmhiR1ZpUUdOaGJHVmlMWEJqTFd4cGJuVjRJQ2hEWVd4bFlpQkViM2h6WlhrcE1CNFhEVEl4TURneE1ERTMKTXpJd09Wb1hEVE14TURneE1ERTNNekl3T1Zvd2dZTXhIakFjQmdOVkJBb1RGVzFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCRFFURXNNQ29HQTFVRUN3d2pZMkZzWldKQVkyRnNaV0l0Y0dNdGJHbHVkWGdnS0VOaGJHVmlJRVJ2CmVITmxlU2t4TXpBeEJnTlZCQU1NS20xclkyVnlkQ0JqWVd4bFlrQmpZV3hsWWkxd1l5MXNhVzUxZUNBb1EyRnMKWldJZ1JHOTRjMlY1S1RDQ0FhSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnR1BBRENDQVlvQ2dnR0JBTmJLeU16NQpNVlc2WUtkamgxb0lOMU1uN1BFMnBINVNiSlNwV3hkQUdoZEJrQmtwQWE3T3hhcmpINUtWa0NUU2E3b25jbGE3CnFOdUpaUzZtQm1veEYrUitjUjNqeUdkVUFZbG96bDFqbGZxTElmQy8rZzdWN1ZtT0puOTh0akI0MmZhdHhMbDYKV1BBdzFKRE5zV3RRZmhLaGJjSHV0N1JzRjByTU9PSGN3eXdUUjdMT3lDbUllbDFwY21wVjRoYlZjVDZlVndvUApIWHlKU2E5Y3FhTVE1WHJkb2dhaTRJcVpaSUdMSGVMc1RWdXRPZ0pGWEVldmxYL1FUM3NXb21FY3R6aDM4SnM0CjlEaUFQRDZkNFk3L0NQTFlFZmsyOUpROU5aaHBnRHNpOWh1NUZISFpjWHdmMUlIbHcvQ0JWZ242aitqbXZLS3oKOTBNYTFvcXV2M1c2ZHR0aWQveENjTEd1MlMrOTZUenJ5a21veTVWYWNMdFZFUDQxWW1vVmxzOTFybG83b2xwZQpRV0Zibm1jbzczOVRJLzRoK0hvZG9scGVyUUVSUWw3dUNucEtWUFozV29rS3VSaDVwa3FrUXAvYXJRanR3Y1J0Ckc0M0NyRHBibCt1U2pNQ0F4aGE5NThlVFl2dG9qVE1udkx0c0dJRDFoR1hucWx3KzVLaktyZ1JIclFJREFRQUIKbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQWdRd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQWRCZ05WSFE0RQpGZ1FVaFlaWVdJQkh5azZaVlRucDNsUnQvdHlCUDAwd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFBMUYvYXByCmw2cE5UM01wL014aFVVZ282dXNFSkNyeUdRY0xSZmV4eVFYR04zaHVDbUlyUDU1VkZhOEVUUEF0anNyNlBNZTcKN3Z2RWo4ZUZ1Mkp0S292bFF3TmV3WVU5Y2pBTUNWYUZpTmJyUWEyMGh6aFdjMmpzNmR5aWxkRTYvRFB6YmVkcwpLREF4aEZOcDM1U2x3dFJ0S2sxU3p4SnhzcVN3amZ4SThmcCtSLzB3TzhnMGZXVGRNMmdDcFJ3WU1Od0pFTEVnCitkU2x2SkN3dXUrcnp4TGFsemFQRjFQTVRXNzJPRUxhbC9qNXNEKzJWeXRRNGsrSFVEYnl0MkRuUVQ3WVEzem8KcTAyeDJ1MnNtMVdXL28vdWg4cGpQeGtHUXFMMm1yeVpzNlZIOVZDVTNRa0tORHNzTmQ3MWxyM3dQb0U0WVJIZQpVdnpEMWVEZWVsekJVRk5JcERDamRDc0w1NXlJUHFVc3I2bG1qcEJQTDB2ZWEzM1FUTWJjc1N4dTB1bUdYRGJVCjY2anVVNFoxak9FMHdDbEl2YU82OTlKK0UyZ0JlMWpVTjZBdDZiOEJTb1pxQ3FYWW9ESEdlaTlSQlVkdmdxdG8Ka1Zzb0pmREkvVEZNZWtZZ3BMNVVWWW1MZGZncUxQUFJQOXBRQkxEeDNtc3plQXFudmZUSUNBemZYZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
CERTIFICATE_KEY: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2d0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktrd2dnU2xBZ0VBQW9JQkFRRGFYVnFaeDFzVy80RHUKOUF1MmdKM2xPYm5tWXNDOGlXYktJMnhRZWtJaWNzQ0cybmpiRU96MzNrYW4vdWxpTW14dkxBdlFHME44Q1N3YwpLOWFqQXJ0cm9sT3pLY1lqMWZTM2YrbnJFZmlrc2J6Y0c0UWIwNzQxS2VxMktkUmRZcEdBNE0rNmNHNEE0L1Z4CkM5bGc1TlQwMld3a1hSVFRVZWNRYkh1NXluUTNyNHUxaTdHdEJvdEM4NFBUaUV1dVFaRGxXMTFMdlI5U1FuWXoKdVlSYzRob1BHWko3V0E0TWN2UjFjczJQdlZTcU5aNzhoZkNEaDJDbWZhTEZBWHFWUlJObG1FZXJTL1o0NTdyZwpseGs5OUpKUGt3UVNabjcrMGtwckoyb25uZG1QWnE3YmdPUU50bXdYVDRxNGNIQUIxck1kRkxHVzgyajBhZ25oCkx1eXgwS25OQWdNQkFBRUNnZ0VCQUxmYjlLWVllalVDQ3dDbmtaa244RXFLY1dGdmN0TU1hZlQzSUlNZWZjTGQKbGdlMXVoN1J3SVR2cmRSVHlSUTZXcHk4bkhHc0V3VkQvOVQwZ0hPZW9Fbi9VclEvRHlzclFqS2pURVQyUzhINApPWW1telhSVXRBbTFjbi9ROXBOdXBBNjh1NHRDa1F6RTQrczhTOXJPc2hRN1lWZTQzQWtXSkJUckVyNGJuZ0VuCmlyU1ZOdDhPQ0E0emxtR0VEYzBEOE1mMTNCbUpOditmNmtpa1p4d1pTUzNKSUwwcWUvcENvYWE5KzMyaVJGRngKVGo2cmlrTHkyYktxMUgwYW02dXViR2UxUEx0ZWpXS3AvcmRQejIza0RVTEJUSS9IZXU5dVlxY1pGZUNlQ2dIeApnWkxvd0d1emJVd0xUQUZqZ3FqSStMdlBuazZyR0dxaURpTkV5SEdqUWFFQ2dZRUE2dnNwQ212SE9iT3JtaU1MCkhpNWFNSTlDQW80c2RXWU5sd2tZdVQyK2tyT0VpM3d6RHNLaVpuUmxTWE1SV2YzVHR1OW9ETkVuNVk2dE9NdHUKVzg3OTUwNEtONmU3Ulk3aXZCQThPSlQxUFd3M3BySEJ4QkNmeEQxd2J3V2MyUGIyQlZnQzd1U01KWHR4UVNaOApLRStmaEwyMHVmL1NMZ0Z3ZTEwVURMbUVqVWtDZ1lFQTdlV3hnbnBpbUZ2UFRZYTBvNHFGQ2RueThPSmQ5V2VMCitZQkkxOWw0Q29yU2pqNkJ1ZmdzcWRDYUZKbDEwTnMwSzFTRldIMEM4Q3JkZkpvV3I4RllsVUphbXpWQUkvTGMKTnQrZG8xTmRCV2Q5ZnBTWk94S0dxOFMxNTZCRVV4cm9lbmdzNFU2bXRlWDMvMzhKbU9va3pYUlVMLzVOQS9BVgpGbFdEV1I0NWpHVUNnWUVBdVFaVFpwVS9KanhIWHZOQkNkN052WGJRTDFycnZ2VkF0akMvZXYwWFZrUnNsYmlTCks0a3VmeVlmcXhva0M0eEdiTUZPV09sSVZRVm5lRlVXN011c09ibkZhZFYxTEd3Nk5JTkVKL21Dc1g3SXcwVXMKb2NuRlE2eHRINzUzcG8rdllMM1FjWE1jdDFiZjhzRHUrbjdYeUpubitKMXJUalpyNzNkM0ZoM3VOYUVDZ1lBQwpCM2FISldJWDZKaVJFYmdTdVFpL2Q4Tnh1SXlTbmtwOFcxTER2SkFnanVTUzRBZWRQWGVzRHlKeFVJbkh1VWJ0Cm82L3JmRTE5SFBCOHNwZkU4Z0krYTYxNEszRWJuV094ZUNEUkZ0SHhUTnV1SzdoTzM2NlVZbjRtdHFBK2tUa3cKYWp2L3cvcjZERGNjVDhvV0t0RWJpNFY0VDFQNjE1NW1iVjVNY1V5T1hRS0JnUURJRFRnYnJGRE9sZ0ozOTVRNApwRWdsdjNUNDA0Wll0N05oUVFNd3FMaC9aYmZMVVhqUk8wZmI2VDZmOEV4L3Q4V1NaQnlVQ1NKcGloRzRXWTFPCnJlYWFhbzIwanVSMVdudU5mWDNiTVhNSEZ0ZEpDOFd1V3ZCK2MvcGttSDZRVFRjMXIySlJ3cEYzWXF0Mi9vVzcKRmFRbUdNNG8vVVBlSWhxaUhqMzZleDBwOGc9PQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==
CLIENT_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
COOKIE_SECRET: UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=
DATABROKER_SERVICE_URL: https://pomerium-databroker:5443
DATABROKER_STORAGE_CONNECTION_STRING: postgres://pomerium:password@postgres:5432/test
DATABROKER_STORAGE_TYPE: postgres
DOWNSTREAM_MTLS_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
ENVOY_ADMIN_ADDRESS: 0.0.0.0:9901
GOOGLE_CLOUD_SERVERLESS_AUTHENTICATION_SERVICE_ACCOUNT: ewoiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImF1dGhfdXJpIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImNsaWVudF9lbWFpbCI6ICJyZWRhY3RlZEBwb21lcml1bS1yZWRhY3RlZC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsCiJjbGllbnRfaWQiOiAiMTAxMjE1OTkwNDU4MDAwMzM0Mzg3IiwKImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVktLS0tLVxuTUlJRXZRSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2N3Z2dTakFnRUFBb0lCQVFDOEhMQkFJelhrUGVlZ1xubGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PL1xuRUtnQ09GRnhVRHFvUjgyaVkwNlNhY0FqSG5pNitQTzl0VlJiRlYwdzE0QkRBSlNwQitWdld5bCtGb1BEVi92c1xuWjMxRnRZdytFd3FrYkR4L2thVDl1emYrTEpkbGtmMTRuUVFqOEVreS84ZDNtV0piYi85dGpPYnNhUWdKNUxMeFxuQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUFxubXFta2F3VVd3M2VraGo4MFNKZy9USzlQUmFOL1Z2Y0kxUGdBZDdMWnp0VVJlU21UeTVoZDlyNnJPQnhweHduVFxuRHZIa0JuNnZBZ01CQUFFQ2dnRUFCMjhpMEFZVU5TYjFKbldGYkt6cnVVY3R1M3RDTlhvdkpnNkszQmlQVk1rcVxuRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBV1xuOGVKZXFSTFpFZnNTU0pPWFRHN1JkR3NuNHFIRkowMHMyWlRsY0lIU1B3bkZtK1hqSmk5OVU4RzRYc1VvWG8wclxuR3krMFZDdVU3TThnSUNFSEhzclFPOVhERDNuVDJqaXU1VGpyS3dqdXQzRW1vSnNzSTVicXgzMytPQnU1QnBDUFxuQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVFxuYkxrTEZ5V0JOVFdVWjJSLzJ3eG11b0M2bUxadzg3OU1MQ0tNdmsxZG9RS0JnUURobXdHYWZKTnltVGlFUVpSSVxuU3NReDRzZXFmT0tmZ0ZDN29ocUg5Y1JPT3U4SUoxbzdxMnBNMlc0WGlWK1Mzd1RkUEdtY2E2SU9qWDIzaXNWQlxuMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzN1xuYXh6bGFNcnhFdTNMSTlVRTdOdHJkUWlCeVFLQmdRRFZkSTZjZUlWQlQ2Umd2Vkd0OHprTGpQSUZqaFFFSEFJcFxudWhpcmdxcFM2Q1g5Qmx5ZjIrbzQwem1majNoZTVyQ2NFb0I1TXNlTStEZ0ZiY1ZoMmUvTVZuWWlOTnc2SkNEQlxuQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleVxudUJIVkJ2LzR0d0tCZ0h3SHVlUHk1U1UxczJxU216RDdXYzJMUGZZdTNuQ09ITlJyRkdiMjZNdVJmdVJlcmk3clxuMkc4VGdvRVNGeWNwMFFUSU44KzFKTTBYWUt4TmNKRDZCOFYxd0tiYnBRc3ltbmVJMWdqdXRpQi9JZ3cvUGtES1xuQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWlxuZk4yWWVZYnlZY2FNMTFwMVZpbHVsVlRWalkzaS9GWmlEUjRTTC9JR0pXak4vU3pnNGlYWXNLRm11K2R1bE9abFxuY0JBTHBFS3JxcG16WFl0ck42YnN2MTgrNWVPM3FHYksyRHJFcTNlV1ZldjJLb1RNb2J4ejdnKytYQklXSm1MQVxuSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkU1xuS3JsdHdtb2RIaXFYTmJWa3diVzFBRlBKYmlZYWk0WUZmSzRJQWJpZi9ZbXhmOUc3OGFPa3I5WnBDSXpPa0RQWlxuWXBFd1FHV3NBaEVsQ0Z2YzhFLzVkSEVTU3ArdFd0UCtObHVpbXBGcWlEZzMvU1VuTXdPMnhIMG5oTGEwemVqaFxuZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9XG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4iLAoicHJpdmF0ZV9rZXlfaWQiOiAiZTA3ZjdjOTM4NzBjN2UwM2Y4ODM1NjBlY2Q4ZmQwZjRkMjdiMDA4MSIsCiJwcm9qZWN0X2lkIjogInBvbWVyaXVtLXJlZGFjdGVkIiwKInRva2VuX3VyaSI6ICJodHRwOi8vbW9jay1pZHA6ODAyNC90b2tlbiIsCiJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIKfQ==
GRPC_ADDRESS: :5443
@ -337,11 +337,11 @@ services:
CERTIFICATE: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVVakNDQXJxZ0F3SUJBZ0lSQUtOYUVxQ21tWmZobWNZZ1p5MDFXQ3N3RFFZSktvWklodmNOQVFFTEJRQXcKZ1lNeEhqQWNCZ05WQkFvVEZXMXJZMlZ5ZENCa1pYWmxiRzl3YldWdWRDQkRRVEVzTUNvR0ExVUVDd3dqWTJGcwpaV0pBWTJGc1pXSXRjR010YkdsdWRYZ2dLRU5oYkdWaUlFUnZlSE5sZVNreE16QXhCZ05WQkFNTUttMXJZMlZ5CmRDQmpZV3hsWWtCallXeGxZaTF3WXkxc2FXNTFlQ0FvUTJGc1pXSWdSRzk0YzJWNUtUQWVGdzB5TVRBNE1UQXgKTnpNeU1UQmFGdzB5TXpFeE1UQXhPRE15TVRCYU1GY3hKekFsQmdOVkJBb1RIbTFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCalpYSjBhV1pwWTJGMFpURXNNQ29HQTFVRUN3d2pZMkZzWldKQVkyRnNaV0l0Y0dNdGJHbHVkWGdnCktFTmhiR1ZpSUVSdmVITmxlU2t3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzgKSExCQUl6WGtQZWVnbGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRAp5VmhEVDBRbEkvTy9FS2dDT0ZGeFVEcW9SODJpWTA2U2FjQWpIbmk2K1BPOXRWUmJGVjB3MTRCREFKU3BCK1Z2Cld5bCtGb1BEVi92c1ozMUZ0WXcrRXdxa2JEeC9rYVQ5dXpmK0xKZGxrZjE0blFRajhFa3kvOGQzbVdKYmIvOXQKak9ic2FRZ0o1TEx4Q1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcQpiWlVERytaaW9BclBtcW1rYXdVV3czZWtoajgwU0pnL1RLOVBSYU4vVnZjSTFQZ0FkN0xaenRVUmVTbVR5NWhkCjlyNnJPQnhweHduVER2SGtCbjZ2QWdNQkFBR2piREJxTUE0R0ExVWREd0VCL3dRRUF3SUZvREFUQmdOVkhTVUUKRERBS0JnZ3JCZ0VGQlFjREFUQWZCZ05WSFNNRUdEQVdnQlNGaGxoWWdFZktUcGxWT2VuZVZHMyszSUUvVFRBaQpCZ05WSFJFRUd6QVpnaGNxTG14dlkyRnNhRzl6ZEM1d2IyMWxjbWwxYlM1cGJ6QU5CZ2txaGtpRzl3MEJBUXNGCkFBT0NBWUVBdWZRQUY3OXM3YzFnbVo5Q0lLQlNHa0hoK1NIMDFDdUtZbm5IaU1vd0hzVGlvRmFVQVFzZC9QNFgKYzJYQnFjMzRlVDNtQ3ZwZ1pqSGJqejZKbG5UWUp4dUx2VnFuVkIzZW10V3JiMWNRdmg4QnBoeHNwVGxTOHVpRQpBRWYvbmd0cHpmQS9mNGxwR2t6clEwY3lQa0VKR3o1MTFxOTdpdHpuOVJaWnpWVFp4TlZGU1AydlZoTk5RVnNXCk94YWtjdllSZ256OEFPUVMzT1BIajJGUWMzaWlic2hjdDVsZUl3WVpGY3hJTkdIUjZLTDYrL0xTZVBOQ0VNbUsKcXltVlBrUUdzSWNVNkdROWZ4YVN1NG1wK0lVQUxQcm9pekVWSThTVms1bk9tM0hJZXorWmZYaHpmbkd4MDZTSQo2TnVvUVFQcVVCZVplWG4yWUZZaGlwZVJkclF4dkEzNi9ZWGEvQWtYQ2VVMHBYeGJ0WEtjdmF0ZnJpNUtuWUpECmtINTlhK2FGa1RzbDQxdGZJMmNuUllWZGRxWFZsM096TGJjZ0FGTG4xV2VDMXh4M3hSWGk3S2xkb2tPbHZndisKQjZuYVdmQ3hSbFdaL2xzbUhhZTRrYzFXSDRLYzduSytJVGI0MEVralY2OC9BN2tyWnNOMVZjcU50cG9tWWtnRQp4alVFOFhVdQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
CERTIFICATE_AUTHORITY: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUxekNDQXorZ0F3SUJBZ0lRWjEzOWNkL3BhUGRrUzJKeUF1N2tFREFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKZ3pFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNU3d3S2dZRFZRUUxEQ05qWVd4bApZa0JqWVd4bFlpMXdZeTFzYVc1MWVDQW9RMkZzWldJZ1JHOTRjMlY1S1RFek1ERUdBMVVFQXd3cWJXdGpaWEowCklHTmhiR1ZpUUdOaGJHVmlMWEJqTFd4cGJuVjRJQ2hEWVd4bFlpQkViM2h6WlhrcE1CNFhEVEl4TURneE1ERTMKTXpJd09Wb1hEVE14TURneE1ERTNNekl3T1Zvd2dZTXhIakFjQmdOVkJBb1RGVzFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCRFFURXNNQ29HQTFVRUN3d2pZMkZzWldKQVkyRnNaV0l0Y0dNdGJHbHVkWGdnS0VOaGJHVmlJRVJ2CmVITmxlU2t4TXpBeEJnTlZCQU1NS20xclkyVnlkQ0JqWVd4bFlrQmpZV3hsWWkxd1l5MXNhVzUxZUNBb1EyRnMKWldJZ1JHOTRjMlY1S1RDQ0FhSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnR1BBRENDQVlvQ2dnR0JBTmJLeU16NQpNVlc2WUtkamgxb0lOMU1uN1BFMnBINVNiSlNwV3hkQUdoZEJrQmtwQWE3T3hhcmpINUtWa0NUU2E3b25jbGE3CnFOdUpaUzZtQm1veEYrUitjUjNqeUdkVUFZbG96bDFqbGZxTElmQy8rZzdWN1ZtT0puOTh0akI0MmZhdHhMbDYKV1BBdzFKRE5zV3RRZmhLaGJjSHV0N1JzRjByTU9PSGN3eXdUUjdMT3lDbUllbDFwY21wVjRoYlZjVDZlVndvUApIWHlKU2E5Y3FhTVE1WHJkb2dhaTRJcVpaSUdMSGVMc1RWdXRPZ0pGWEVldmxYL1FUM3NXb21FY3R6aDM4SnM0CjlEaUFQRDZkNFk3L0NQTFlFZmsyOUpROU5aaHBnRHNpOWh1NUZISFpjWHdmMUlIbHcvQ0JWZ242aitqbXZLS3oKOTBNYTFvcXV2M1c2ZHR0aWQveENjTEd1MlMrOTZUenJ5a21veTVWYWNMdFZFUDQxWW1vVmxzOTFybG83b2xwZQpRV0Zibm1jbzczOVRJLzRoK0hvZG9scGVyUUVSUWw3dUNucEtWUFozV29rS3VSaDVwa3FrUXAvYXJRanR3Y1J0Ckc0M0NyRHBibCt1U2pNQ0F4aGE5NThlVFl2dG9qVE1udkx0c0dJRDFoR1hucWx3KzVLaktyZ1JIclFJREFRQUIKbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQWdRd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQWRCZ05WSFE0RQpGZ1FVaFlaWVdJQkh5azZaVlRucDNsUnQvdHlCUDAwd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFBMUYvYXByCmw2cE5UM01wL014aFVVZ282dXNFSkNyeUdRY0xSZmV4eVFYR04zaHVDbUlyUDU1VkZhOEVUUEF0anNyNlBNZTcKN3Z2RWo4ZUZ1Mkp0S292bFF3TmV3WVU5Y2pBTUNWYUZpTmJyUWEyMGh6aFdjMmpzNmR5aWxkRTYvRFB6YmVkcwpLREF4aEZOcDM1U2x3dFJ0S2sxU3p4SnhzcVN3amZ4SThmcCtSLzB3TzhnMGZXVGRNMmdDcFJ3WU1Od0pFTEVnCitkU2x2SkN3dXUrcnp4TGFsemFQRjFQTVRXNzJPRUxhbC9qNXNEKzJWeXRRNGsrSFVEYnl0MkRuUVQ3WVEzem8KcTAyeDJ1MnNtMVdXL28vdWg4cGpQeGtHUXFMMm1yeVpzNlZIOVZDVTNRa0tORHNzTmQ3MWxyM3dQb0U0WVJIZQpVdnpEMWVEZWVsekJVRk5JcERDamRDc0w1NXlJUHFVc3I2bG1qcEJQTDB2ZWEzM1FUTWJjc1N4dTB1bUdYRGJVCjY2anVVNFoxak9FMHdDbEl2YU82OTlKK0UyZ0JlMWpVTjZBdDZiOEJTb1pxQ3FYWW9ESEdlaTlSQlVkdmdxdG8Ka1Zzb0pmREkvVEZNZWtZZ3BMNVVWWW1MZGZncUxQUFJQOXBRQkxEeDNtc3plQXFudmZUSUNBemZYZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
CERTIFICATE_KEY: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzhITEJBSXpYa1BlZWcKbGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PLwpFS2dDT0ZGeFVEcW9SODJpWTA2U2FjQWpIbmk2K1BPOXRWUmJGVjB3MTRCREFKU3BCK1Z2V3lsK0ZvUERWL3ZzClozMUZ0WXcrRXdxa2JEeC9rYVQ5dXpmK0xKZGxrZjE0blFRajhFa3kvOGQzbVdKYmIvOXRqT2JzYVFnSjVMTHgKQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUAptcW1rYXdVV3czZWtoajgwU0pnL1RLOVBSYU4vVnZjSTFQZ0FkN0xaenRVUmVTbVR5NWhkOXI2ck9CeHB4d25UCkR2SGtCbjZ2QWdNQkFBRUNnZ0VBQjI4aTBBWVVOU2IxSm5XRmJLenJ1VWN0dTN0Q05Yb3ZKZzZLM0JpUFZNa3EKRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBVwo4ZUplcVJMWkVmc1NTSk9YVEc3UmRHc240cUhGSjAwczJaVGxjSUhTUHduRm0rWGpKaTk5VThHNFhzVW9YbzByCkd5KzBWQ3VVN004Z0lDRUhIc3JRTzlYREQzblQyaml1NVRqckt3anV0M0Vtb0pzc0k1YnF4MzMrT0J1NUJwQ1AKQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVApiTGtMRnlXQk5UV1VaMlIvMnd4bXVvQzZtTFp3ODc5TUxDS012azFkb1FLQmdRRGhtd0dhZkpOeW1UaUVRWlJJClNzUXg0c2VxZk9LZmdGQzdvaHFIOWNST091OElKMW83cTJwTTJXNFhpVitTM3dUZFBHbWNhNklPalgyM2lzVkIKMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzNwpheHpsYU1yeEV1M0xJOVVFN050cmRRaUJ5UUtCZ1FEVmRJNmNlSVZCVDZSZ3ZWR3Q4emtMalBJRmpoUUVIQUlwCnVoaXJncXBTNkNYOUJseWYyK280MHptZmozaGU1ckNjRW9CNU1zZU0rRGdGYmNWaDJlL01WbllpTk53NkpDREIKQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleQp1QkhWQnYvNHR3S0JnSHdIdWVQeTVTVTFzMnFTbXpEN1djMkxQZll1M25DT0hOUnJGR2IyNk11UmZ1UmVyaTdyCjJHOFRnb0VTRnljcDBRVElOOCsxSk0wWFlLeE5jSkQ2QjhWMXdLYmJwUXN5bW5lSTFnanV0aUIvSWd3L1BrREsKQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWgpmTjJZZVlieVljYU0xMXAxVmlsdWxWVFZqWTNpL0ZaaURSNFNML0lHSldqTi9Temc0aVhZc0tGbXUrZHVsT1psCmNCQUxwRUtycXBtelhZdHJONmJzdjE4KzVlTzNxR2JLMkRyRXEzZVdWZXYyS29UTW9ieHo3ZysrWEJJV0ptTEEKSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkUwpLcmx0d21vZEhpcVhOYlZrd2JXMUFGUEpiaVlhaTRZRmZLNElBYmlmL1lteGY5Rzc4YU9rcjlacENJek9rRFBaCllwRXdRR1dzQWhFbENGdmM4RS81ZEhFU1NwK3RXdFArTmx1aW1wRnFpRGczL1NVbk13TzJ4SDBuaExhMHplamgKZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
CLIENT_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
COOKIE_SECRET: UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=
DATABROKER_SERVICE_URL: https://pomerium-databroker:5443
DATABROKER_STORAGE_CONNECTION_STRING: postgres://pomerium:password@postgres:5432/test
DATABROKER_STORAGE_TYPE: postgres
DOWNSTREAM_MTLS_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
ENVOY_ADMIN_ADDRESS: 0.0.0.0:9901
GOOGLE_CLOUD_SERVERLESS_AUTHENTICATION_SERVICE_ACCOUNT: ewoiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImF1dGhfdXJpIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImNsaWVudF9lbWFpbCI6ICJyZWRhY3RlZEBwb21lcml1bS1yZWRhY3RlZC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsCiJjbGllbnRfaWQiOiAiMTAxMjE1OTkwNDU4MDAwMzM0Mzg3IiwKImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVktLS0tLVxuTUlJRXZRSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2N3Z2dTakFnRUFBb0lCQVFDOEhMQkFJelhrUGVlZ1xubGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PL1xuRUtnQ09GRnhVRHFvUjgyaVkwNlNhY0FqSG5pNitQTzl0VlJiRlYwdzE0QkRBSlNwQitWdld5bCtGb1BEVi92c1xuWjMxRnRZdytFd3FrYkR4L2thVDl1emYrTEpkbGtmMTRuUVFqOEVreS84ZDNtV0piYi85dGpPYnNhUWdKNUxMeFxuQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUFxubXFta2F3VVd3M2VraGo4MFNKZy9USzlQUmFOL1Z2Y0kxUGdBZDdMWnp0VVJlU21UeTVoZDlyNnJPQnhweHduVFxuRHZIa0JuNnZBZ01CQUFFQ2dnRUFCMjhpMEFZVU5TYjFKbldGYkt6cnVVY3R1M3RDTlhvdkpnNkszQmlQVk1rcVxuRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBV1xuOGVKZXFSTFpFZnNTU0pPWFRHN1JkR3NuNHFIRkowMHMyWlRsY0lIU1B3bkZtK1hqSmk5OVU4RzRYc1VvWG8wclxuR3krMFZDdVU3TThnSUNFSEhzclFPOVhERDNuVDJqaXU1VGpyS3dqdXQzRW1vSnNzSTVicXgzMytPQnU1QnBDUFxuQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVFxuYkxrTEZ5V0JOVFdVWjJSLzJ3eG11b0M2bUxadzg3OU1MQ0tNdmsxZG9RS0JnUURobXdHYWZKTnltVGlFUVpSSVxuU3NReDRzZXFmT0tmZ0ZDN29ocUg5Y1JPT3U4SUoxbzdxMnBNMlc0WGlWK1Mzd1RkUEdtY2E2SU9qWDIzaXNWQlxuMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzN1xuYXh6bGFNcnhFdTNMSTlVRTdOdHJkUWlCeVFLQmdRRFZkSTZjZUlWQlQ2Umd2Vkd0OHprTGpQSUZqaFFFSEFJcFxudWhpcmdxcFM2Q1g5Qmx5ZjIrbzQwem1majNoZTVyQ2NFb0I1TXNlTStEZ0ZiY1ZoMmUvTVZuWWlOTnc2SkNEQlxuQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleVxudUJIVkJ2LzR0d0tCZ0h3SHVlUHk1U1UxczJxU216RDdXYzJMUGZZdTNuQ09ITlJyRkdiMjZNdVJmdVJlcmk3clxuMkc4VGdvRVNGeWNwMFFUSU44KzFKTTBYWUt4TmNKRDZCOFYxd0tiYnBRc3ltbmVJMWdqdXRpQi9JZ3cvUGtES1xuQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWlxuZk4yWWVZYnlZY2FNMTFwMVZpbHVsVlRWalkzaS9GWmlEUjRTTC9JR0pXak4vU3pnNGlYWXNLRm11K2R1bE9abFxuY0JBTHBFS3JxcG16WFl0ck42YnN2MTgrNWVPM3FHYksyRHJFcTNlV1ZldjJLb1RNb2J4ejdnKytYQklXSm1MQVxuSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkU1xuS3JsdHdtb2RIaXFYTmJWa3diVzFBRlBKYmlZYWk0WUZmSzRJQWJpZi9ZbXhmOUc3OGFPa3I5WnBDSXpPa0RQWlxuWXBFd1FHV3NBaEVsQ0Z2YzhFLzVkSEVTU3ArdFd0UCtObHVpbXBGcWlEZzMvU1VuTXdPMnhIMG5oTGEwemVqaFxuZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9XG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4iLAoicHJpdmF0ZV9rZXlfaWQiOiAiZTA3ZjdjOTM4NzBjN2UwM2Y4ODM1NjBlY2Q4ZmQwZjRkMjdiMDA4MSIsCiJwcm9qZWN0X2lkIjogInBvbWVyaXVtLXJlZGFjdGVkIiwKInRva2VuX3VyaSI6ICJodHRwOi8vbW9jay1pZHA6ODAyNC90b2tlbiIsCiJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIKfQ==
GRPC_ADDRESS: :5443

View file

@ -157,10 +157,10 @@ services:
CERTIFICATE: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVVakNDQXJxZ0F3SUJBZ0lSQUtOYUVxQ21tWmZobWNZZ1p5MDFXQ3N3RFFZSktvWklodmNOQVFFTEJRQXcKZ1lNeEhqQWNCZ05WQkFvVEZXMXJZMlZ5ZENCa1pYWmxiRzl3YldWdWRDQkRRVEVzTUNvR0ExVUVDd3dqWTJGcwpaV0pBWTJGc1pXSXRjR010YkdsdWRYZ2dLRU5oYkdWaUlFUnZlSE5sZVNreE16QXhCZ05WQkFNTUttMXJZMlZ5CmRDQmpZV3hsWWtCallXeGxZaTF3WXkxc2FXNTFlQ0FvUTJGc1pXSWdSRzk0YzJWNUtUQWVGdzB5TVRBNE1UQXgKTnpNeU1UQmFGdzB5TXpFeE1UQXhPRE15TVRCYU1GY3hKekFsQmdOVkJBb1RIbTFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCalpYSjBhV1pwWTJGMFpURXNNQ29HQTFVRUN3d2pZMkZzWldKQVkyRnNaV0l0Y0dNdGJHbHVkWGdnCktFTmhiR1ZpSUVSdmVITmxlU2t3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQzgKSExCQUl6WGtQZWVnbGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRAp5VmhEVDBRbEkvTy9FS2dDT0ZGeFVEcW9SODJpWTA2U2FjQWpIbmk2K1BPOXRWUmJGVjB3MTRCREFKU3BCK1Z2Cld5bCtGb1BEVi92c1ozMUZ0WXcrRXdxa2JEeC9rYVQ5dXpmK0xKZGxrZjE0blFRajhFa3kvOGQzbVdKYmIvOXQKak9ic2FRZ0o1TEx4Q1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcQpiWlVERytaaW9BclBtcW1rYXdVV3czZWtoajgwU0pnL1RLOVBSYU4vVnZjSTFQZ0FkN0xaenRVUmVTbVR5NWhkCjlyNnJPQnhweHduVER2SGtCbjZ2QWdNQkFBR2piREJxTUE0R0ExVWREd0VCL3dRRUF3SUZvREFUQmdOVkhTVUUKRERBS0JnZ3JCZ0VGQlFjREFUQWZCZ05WSFNNRUdEQVdnQlNGaGxoWWdFZktUcGxWT2VuZVZHMyszSUUvVFRBaQpCZ05WSFJFRUd6QVpnaGNxTG14dlkyRnNhRzl6ZEM1d2IyMWxjbWwxYlM1cGJ6QU5CZ2txaGtpRzl3MEJBUXNGCkFBT0NBWUVBdWZRQUY3OXM3YzFnbVo5Q0lLQlNHa0hoK1NIMDFDdUtZbm5IaU1vd0hzVGlvRmFVQVFzZC9QNFgKYzJYQnFjMzRlVDNtQ3ZwZ1pqSGJqejZKbG5UWUp4dUx2VnFuVkIzZW10V3JiMWNRdmg4QnBoeHNwVGxTOHVpRQpBRWYvbmd0cHpmQS9mNGxwR2t6clEwY3lQa0VKR3o1MTFxOTdpdHpuOVJaWnpWVFp4TlZGU1AydlZoTk5RVnNXCk94YWtjdllSZ256OEFPUVMzT1BIajJGUWMzaWlic2hjdDVsZUl3WVpGY3hJTkdIUjZLTDYrL0xTZVBOQ0VNbUsKcXltVlBrUUdzSWNVNkdROWZ4YVN1NG1wK0lVQUxQcm9pekVWSThTVms1bk9tM0hJZXorWmZYaHpmbkd4MDZTSQo2TnVvUVFQcVVCZVplWG4yWUZZaGlwZVJkclF4dkEzNi9ZWGEvQWtYQ2VVMHBYeGJ0WEtjdmF0ZnJpNUtuWUpECmtINTlhK2FGa1RzbDQxdGZJMmNuUllWZGRxWFZsM096TGJjZ0FGTG4xV2VDMXh4M3hSWGk3S2xkb2tPbHZndisKQjZuYVdmQ3hSbFdaL2xzbUhhZTRrYzFXSDRLYzduSytJVGI0MEVralY2OC9BN2tyWnNOMVZjcU50cG9tWWtnRQp4alVFOFhVdQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
CERTIFICATE_AUTHORITY: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUxekNDQXorZ0F3SUJBZ0lRWjEzOWNkL3BhUGRrUzJKeUF1N2tFREFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKZ3pFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNU3d3S2dZRFZRUUxEQ05qWVd4bApZa0JqWVd4bFlpMXdZeTFzYVc1MWVDQW9RMkZzWldJZ1JHOTRjMlY1S1RFek1ERUdBMVVFQXd3cWJXdGpaWEowCklHTmhiR1ZpUUdOaGJHVmlMWEJqTFd4cGJuVjRJQ2hEWVd4bFlpQkViM2h6WlhrcE1CNFhEVEl4TURneE1ERTMKTXpJd09Wb1hEVE14TURneE1ERTNNekl3T1Zvd2dZTXhIakFjQmdOVkJBb1RGVzFyWTJWeWRDQmtaWFpsYkc5dwpiV1Z1ZENCRFFURXNNQ29HQTFVRUN3d2pZMkZzWldKQVkyRnNaV0l0Y0dNdGJHbHVkWGdnS0VOaGJHVmlJRVJ2CmVITmxlU2t4TXpBeEJnTlZCQU1NS20xclkyVnlkQ0JqWVd4bFlrQmpZV3hsWWkxd1l5MXNhVzUxZUNBb1EyRnMKWldJZ1JHOTRjMlY1S1RDQ0FhSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnR1BBRENDQVlvQ2dnR0JBTmJLeU16NQpNVlc2WUtkamgxb0lOMU1uN1BFMnBINVNiSlNwV3hkQUdoZEJrQmtwQWE3T3hhcmpINUtWa0NUU2E3b25jbGE3CnFOdUpaUzZtQm1veEYrUitjUjNqeUdkVUFZbG96bDFqbGZxTElmQy8rZzdWN1ZtT0puOTh0akI0MmZhdHhMbDYKV1BBdzFKRE5zV3RRZmhLaGJjSHV0N1JzRjByTU9PSGN3eXdUUjdMT3lDbUllbDFwY21wVjRoYlZjVDZlVndvUApIWHlKU2E5Y3FhTVE1WHJkb2dhaTRJcVpaSUdMSGVMc1RWdXRPZ0pGWEVldmxYL1FUM3NXb21FY3R6aDM4SnM0CjlEaUFQRDZkNFk3L0NQTFlFZmsyOUpROU5aaHBnRHNpOWh1NUZISFpjWHdmMUlIbHcvQ0JWZ242aitqbXZLS3oKOTBNYTFvcXV2M1c2ZHR0aWQveENjTEd1MlMrOTZUenJ5a21veTVWYWNMdFZFUDQxWW1vVmxzOTFybG83b2xwZQpRV0Zibm1jbzczOVRJLzRoK0hvZG9scGVyUUVSUWw3dUNucEtWUFozV29rS3VSaDVwa3FrUXAvYXJRanR3Y1J0Ckc0M0NyRHBibCt1U2pNQ0F4aGE5NThlVFl2dG9qVE1udkx0c0dJRDFoR1hucWx3KzVLaktyZ1JIclFJREFRQUIKbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQWdRd0VnWURWUjBUQVFIL0JBZ3dCZ0VCL3dJQkFEQWRCZ05WSFE0RQpGZ1FVaFlaWVdJQkh5azZaVlRucDNsUnQvdHlCUDAwd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dHQkFBMUYvYXByCmw2cE5UM01wL014aFVVZ282dXNFSkNyeUdRY0xSZmV4eVFYR04zaHVDbUlyUDU1VkZhOEVUUEF0anNyNlBNZTcKN3Z2RWo4ZUZ1Mkp0S292bFF3TmV3WVU5Y2pBTUNWYUZpTmJyUWEyMGh6aFdjMmpzNmR5aWxkRTYvRFB6YmVkcwpLREF4aEZOcDM1U2x3dFJ0S2sxU3p4SnhzcVN3amZ4SThmcCtSLzB3TzhnMGZXVGRNMmdDcFJ3WU1Od0pFTEVnCitkU2x2SkN3dXUrcnp4TGFsemFQRjFQTVRXNzJPRUxhbC9qNXNEKzJWeXRRNGsrSFVEYnl0MkRuUVQ3WVEzem8KcTAyeDJ1MnNtMVdXL28vdWg4cGpQeGtHUXFMMm1yeVpzNlZIOVZDVTNRa0tORHNzTmQ3MWxyM3dQb0U0WVJIZQpVdnpEMWVEZWVsekJVRk5JcERDamRDc0w1NXlJUHFVc3I2bG1qcEJQTDB2ZWEzM1FUTWJjc1N4dTB1bUdYRGJVCjY2anVVNFoxak9FMHdDbEl2YU82OTlKK0UyZ0JlMWpVTjZBdDZiOEJTb1pxQ3FYWW9ESEdlaTlSQlVkdmdxdG8Ka1Zzb0pmREkvVEZNZWtZZ3BMNVVWWW1MZGZncUxQUFJQOXBRQkxEeDNtc3plQXFudmZUSUNBemZYZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
CERTIFICATE_KEY: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzhITEJBSXpYa1BlZWcKbGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PLwpFS2dDT0ZGeFVEcW9SODJpWTA2U2FjQWpIbmk2K1BPOXRWUmJGVjB3MTRCREFKU3BCK1Z2V3lsK0ZvUERWL3ZzClozMUZ0WXcrRXdxa2JEeC9rYVQ5dXpmK0xKZGxrZjE0blFRajhFa3kvOGQzbVdKYmIvOXRqT2JzYVFnSjVMTHgKQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUAptcW1rYXdVV3czZWtoajgwU0pnL1RLOVBSYU4vVnZjSTFQZ0FkN0xaenRVUmVTbVR5NWhkOXI2ck9CeHB4d25UCkR2SGtCbjZ2QWdNQkFBRUNnZ0VBQjI4aTBBWVVOU2IxSm5XRmJLenJ1VWN0dTN0Q05Yb3ZKZzZLM0JpUFZNa3EKRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBVwo4ZUplcVJMWkVmc1NTSk9YVEc3UmRHc240cUhGSjAwczJaVGxjSUhTUHduRm0rWGpKaTk5VThHNFhzVW9YbzByCkd5KzBWQ3VVN004Z0lDRUhIc3JRTzlYREQzblQyaml1NVRqckt3anV0M0Vtb0pzc0k1YnF4MzMrT0J1NUJwQ1AKQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVApiTGtMRnlXQk5UV1VaMlIvMnd4bXVvQzZtTFp3ODc5TUxDS012azFkb1FLQmdRRGhtd0dhZkpOeW1UaUVRWlJJClNzUXg0c2VxZk9LZmdGQzdvaHFIOWNST091OElKMW83cTJwTTJXNFhpVitTM3dUZFBHbWNhNklPalgyM2lzVkIKMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzNwpheHpsYU1yeEV1M0xJOVVFN050cmRRaUJ5UUtCZ1FEVmRJNmNlSVZCVDZSZ3ZWR3Q4emtMalBJRmpoUUVIQUlwCnVoaXJncXBTNkNYOUJseWYyK280MHptZmozaGU1ckNjRW9CNU1zZU0rRGdGYmNWaDJlL01WbllpTk53NkpDREIKQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleQp1QkhWQnYvNHR3S0JnSHdIdWVQeTVTVTFzMnFTbXpEN1djMkxQZll1M25DT0hOUnJGR2IyNk11UmZ1UmVyaTdyCjJHOFRnb0VTRnljcDBRVElOOCsxSk0wWFlLeE5jSkQ2QjhWMXdLYmJwUXN5bW5lSTFnanV0aUIvSWd3L1BrREsKQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWgpmTjJZZVlieVljYU0xMXAxVmlsdWxWVFZqWTNpL0ZaaURSNFNML0lHSldqTi9Temc0aVhZc0tGbXUrZHVsT1psCmNCQUxwRUtycXBtelhZdHJONmJzdjE4KzVlTzNxR2JLMkRyRXEzZVdWZXYyS29UTW9ieHo3ZysrWEJJV0ptTEEKSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkUwpLcmx0d21vZEhpcVhOYlZrd2JXMUFGUEpiaVlhaTRZRmZLNElBYmlmL1lteGY5Rzc4YU9rcjlacENJek9rRFBaCllwRXdRR1dzQWhFbENGdmM4RS81ZEhFU1NwK3RXdFArTmx1aW1wRnFpRGczL1NVbk13TzJ4SDBuaExhMHplamgKZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
CLIENT_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
COOKIE_SECRET: UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=
DATABROKER_STORAGE_CONNECTION_STRING: postgres://pomerium:password@postgres:5432/test
DATABROKER_STORAGE_TYPE: postgres
DOWNSTREAM_MTLS_CRL: LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tCk1JSUNXakNCd3dJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURBNk1SNHdIQVlEVlFRS0V4VnRhMk5sY25RZ1pHVjIKWld4dmNHMWxiblFnUTBFeEdEQVdCZ05WQkFNVEQyUnZkMjV6ZEhKbFlXMGdRMEVnTVJjTk1qTXdOekU1TWpFeApPRFExV2hjTk16TXdOekUyTWpFeE9EUTFXakFqTUNFQ0VFWTlqblU4Vmt0Mk1ZdWVza1JkN2J3WERUSXpNRGN4Ck9USXhNVGMwTjFxZ01EQXVNQjhHQTFVZEl3UVlNQmFBRk5IMU5BejhVajI0UGhDR2RCa0dpMENNUUdNTE1Bc0cKQTFVZEZBUUVBZ0lRQURBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVlFQTR3M293NGoxRGF1ZmlCQlhoZEMwRUN5WQp6RHhPdUFDZFI0enlvWWJqTjFnMmtjMGJ1Y2hKNytWMGVUWS9SblNOYyt1cU5ZK0xZcHJYUXF1WktscjlkRlVyCnZKL3BYSit1eUxSL016ZWhpVHIzSG9UTENQbGlLWkREYXlQbW9admFxSEQ4SW9HRW5RWDZrQ0Vob3BiN2d0cUoKVTdUZkhhZXhpMHA0M0ZIMDBnblpmYURNa2NBZDh6Q2xzRVhVckFGQ1FSRDFNNVB1Q09UTzdDZVFjSTUzdUJ2ZAo4YUd2eUhsS0EvMk8xN2duaU1uZ2NvQ083Mk5BVWx0SnpNYnVncWVYT29pR0hZb1NzS1RiWTdNZExoWTNNRUJhCjNaa0NGZ3QzSExIVHo1UzBQZUJWclQ3L3k3U3o1Y2owUUEwSktMM0ozcHNuZ1ZicFM0b0h1NmN5dmcvLzdOZEcKS05CcWRhcytLUEFzbVYrM3k2NENyMmhuditXc1dqaXV4RGdJRUZ6cFFPY3lOT1p6bUlTQUN3N1lYandGdUluZQpPaWlNdVlzLzJOdndRMU9QZnEzamczSWY4a0JVY1NWaCtUZTRGSTMrMDd0V1V2TjZuVllDNFZtWEFjRzFIdXhRCkdubmU5ZjVoZ0VKUFZmTFQrdUozMVZWMTYrdkJuWkQ4NURaSlRyRE0KLS0tLS1FTkQgWDUwOSBDUkwtLS0tLQotLS0tLUJFR0lOIFg1MDkgQ1JMLS0tLS0KTUlJQ05UQ0JuZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREE2TVI0d0hBWURWUVFLRXhWdGEyTmxjblFnWkdWMgpaV3h2Y0cxbGJuUWdRMEV4R0RBV0JnTlZCQU1URDJSdmQyNXpkSEpsWVcwZ1EwRWdNaGNOTWpNd056RTVNakUxCk1ERTFXaGNOTXpNd056RTJNakUxTURFMVdxQXdNQzR3SHdZRFZSMGpCQmd3Rm9BVUN4UTJjQmE1WXpxVnphbXAKaU5DeDhLd0ZGeVF3Q3dZRFZSMFVCQVFDQWhBQU1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQmdRQ1lhbXg4cE0rUgpDbHlza2N1N291aHUvUjFKeTFuV0d5V3RLcGhZcTBYRmJPTGxuazJaN2VEZkFYOEVlajJGYXZxeHphcFIyeDJPCjRpSk5EQ21pd1lZWVVTMlgyTEozclJSSlh5WHZXaHRmSHJ4VVJkNkJpdEMySVhweWtCdFZsZjN6QW5aOEdaRlEKUzFqZGZ5TE11RUFpRHdJYWkzWXQ4SHNEcC9xRzA4OW9YY29TdHlRZy91UnBtV3kwNUE5dUNWT2ZOSFNMU1p1OApscjRxYXRsZXUwd1diVjFhbUw4dE85eDRDUmtPMG8xWWFRcTREb09ydVByKzNOa1RtUHZHaWRoM0Y3MVY2SUVBCmgrS3pkYlJYeEZtQ0NXTFdtcEpEY3JnUjdLVXFaT2hVVXQrRFVxYXFoVjQ0cUkwbnJwUitRWkxvaG9Eb3I5THcKSyt1ZmozbjI5ZVNSWCszUHgrb1ZXUFQ4WVpQMnVLUGRpemk5Nm1lMmpXVHI1MXg5QWpFb0pEc1RuWVJsOSt1WQpTaGlVeFduVGRRc29va25JZmNTLzB6ZmdaODdHdlVWemluQ1F6SnB3VnhkNEFsdDhBbFIrZlhBcU5Jb09ndXl2CnAvQ3RSVm5qVkU3bDdIVy9oUVJxMUowaWpDQ0t3bXlmL0tUZDZFSzRUZHJ2YlgvVTltc1ZNOFk9Ci0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0K
ENVOY_ADMIN_ADDRESS: 0.0.0.0:9901
GOOGLE_CLOUD_SERVERLESS_AUTHENTICATION_SERVICE_ACCOUNT: ewoiYXV0aF9wcm92aWRlcl94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImF1dGhfdXJpIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKImNsaWVudF9lbWFpbCI6ICJyZWRhY3RlZEBwb21lcml1bS1yZWRhY3RlZC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsCiJjbGllbnRfaWQiOiAiMTAxMjE1OTkwNDU4MDAwMzM0Mzg3IiwKImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHA6Ly9tb2NrLWlkcDo4MDI0IiwKInByaXZhdGVfa2V5IjogIi0tLS0tQkVHSU4gUFJJVkFURSBLRVktLS0tLVxuTUlJRXZRSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2N3Z2dTakFnRUFBb0lCQVFDOEhMQkFJelhrUGVlZ1xubGRVZlJLSzJqUXhTVlpENWcrcXNqQXpwbXJxL0F0bXdlSzFjR2NPdFo2ZU9MK3A4YnJQRHlWaERUMFFsSS9PL1xuRUtnQ09GRnhVRHFvUjgyaVkwNlNhY0FqSG5pNitQTzl0VlJiRlYwdzE0QkRBSlNwQitWdld5bCtGb1BEVi92c1xuWjMxRnRZdytFd3FrYkR4L2thVDl1emYrTEpkbGtmMTRuUVFqOEVreS84ZDNtV0piYi85dGpPYnNhUWdKNUxMeFxuQ1lkSW1rcjc3WDJMTXVEdy8xdHBINjQyR0UyNU5yZ202UUhseUtTZllYbzM4djgzZWJFcWJaVURHK1ppb0FyUFxubXFta2F3VVd3M2VraGo4MFNKZy9USzlQUmFOL1Z2Y0kxUGdBZDdMWnp0VVJlU21UeTVoZDlyNnJPQnhweHduVFxuRHZIa0JuNnZBZ01CQUFFQ2dnRUFCMjhpMEFZVU5TYjFKbldGYkt6cnVVY3R1M3RDTlhvdkpnNkszQmlQVk1rcVxuRFQxWHJKSWdGNVJISE9scjNPc0xFNnU3WHoyY3RkTUw2UHNoaUtUdEl3dEdwaXZnUnBDaUpFc2xtcjJ6aThBV1xuOGVKZXFSTFpFZnNTU0pPWFRHN1JkR3NuNHFIRkowMHMyWlRsY0lIU1B3bkZtK1hqSmk5OVU4RzRYc1VvWG8wclxuR3krMFZDdVU3TThnSUNFSEhzclFPOVhERDNuVDJqaXU1VGpyS3dqdXQzRW1vSnNzSTVicXgzMytPQnU1QnBDUFxuQ1Q0NzNENDNQOXAzcWkvWG5mdnFHU0cyT2o0T2FqVjRmcjBvOUIzS3ZJeGtNZW03V2xJM2p5eTFrQXB5WHFWVFxuYkxrTEZ5V0JOVFdVWjJSLzJ3eG11b0M2bUxadzg3OU1MQ0tNdmsxZG9RS0JnUURobXdHYWZKTnltVGlFUVpSSVxuU3NReDRzZXFmT0tmZ0ZDN29ocUg5Y1JPT3U4SUoxbzdxMnBNMlc0WGlWK1Mzd1RkUEdtY2E2SU9qWDIzaXNWQlxuMnVxTmk5UzRNbkkyL2QyMkdkL0JSOXJ2QncxZUdKb0ticld4MjJmRThRQ0VXVDFBbk8rRHVEMGpDODV5UmxzN1xuYXh6bGFNcnhFdTNMSTlVRTdOdHJkUWlCeVFLQmdRRFZkSTZjZUlWQlQ2Umd2Vkd0OHprTGpQSUZqaFFFSEFJcFxudWhpcmdxcFM2Q1g5Qmx5ZjIrbzQwem1majNoZTVyQ2NFb0I1TXNlTStEZ0ZiY1ZoMmUvTVZuWWlOTnc2SkNEQlxuQlFrRjQwOHBacFNlS1h2TC9veVYva0ltTVRKL3RVRFkwRVh4TXdTUEpCMFdsdGJXcmVWSUhvcGlnWFJDYmFleVxudUJIVkJ2LzR0d0tCZ0h3SHVlUHk1U1UxczJxU216RDdXYzJMUGZZdTNuQ09ITlJyRkdiMjZNdVJmdVJlcmk3clxuMkc4VGdvRVNGeWNwMFFUSU44KzFKTTBYWUt4TmNKRDZCOFYxd0tiYnBRc3ltbmVJMWdqdXRpQi9JZ3cvUGtES1xuQ0w0VlA0RjRkYTVOV1cxeVdnTnlnTG9KdlovNXFpS0tpc0pjMEdXazRIS3o2bUxnek9qUTJMSnhBb0dCQUxIWlxuZk4yWWVZYnlZY2FNMTFwMVZpbHVsVlRWalkzaS9GWmlEUjRTTC9JR0pXak4vU3pnNGlYWXNLRm11K2R1bE9abFxuY0JBTHBFS3JxcG16WFl0ck42YnN2MTgrNWVPM3FHYksyRHJFcTNlV1ZldjJLb1RNb2J4ejdnKytYQklXSm1MQVxuSGhhYTZJaVBrWUQ1eXlWeUhLRGJlWGdiM285ZXFDUjd3N2ZZTGp5L0FvR0FJNEQrTUZraXZ3VUY3aHFmNWVkU1xuS3JsdHdtb2RIaXFYTmJWa3diVzFBRlBKYmlZYWk0WUZmSzRJQWJpZi9ZbXhmOUc3OGFPa3I5WnBDSXpPa0RQWlxuWXBFd1FHV3NBaEVsQ0Z2YzhFLzVkSEVTU3ArdFd0UCtObHVpbXBGcWlEZzMvU1VuTXdPMnhIMG5oTGEwemVqaFxuZ21MaDR3L0NjUHliOVp5WGNlV1UvblU9XG4tLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tXG4iLAoicHJpdmF0ZV9rZXlfaWQiOiAiZTA3ZjdjOTM4NzBjN2UwM2Y4ODM1NjBlY2Q4ZmQwZjRkMjdiMDA4MSIsCiJwcm9qZWN0X2lkIjogInBvbWVyaXVtLXJlZGFjdGVkIiwKInRva2VuX3VyaSI6ICJodHRwOi8vbW9jay1pZHA6ODAyNC90b2tlbiIsCiJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIKfQ==
IDP_CLIENT_ID: CLIENT_ID

View file

@ -80,10 +80,10 @@ local Environment(mode, idp, dns_suffix) =
CERTIFICATE: std.base64(importstr '../files/trusted.pem'),
CERTIFICATE_KEY: std.base64(importstr '../files/trusted-key.pem'),
CERTIFICATE_AUTHORITY: std.base64(importstr '../files/ca.pem'),
CLIENT_CRL: std.base64(importstr '../files/downstream-crl.pem'),
COOKIE_SECRET: 'UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=',
DATABROKER_STORAGE_TYPE: 'postgres',
DATABROKER_STORAGE_CONNECTION_STRING: 'postgres://pomerium:password@postgres:5432/test',
DOWNSTREAM_MTLS_CRL: std.base64(importstr '../files/downstream-crl.pem'),
ENVOY_ADMIN_ADDRESS: '0.0.0.0:9901',
GOOGLE_CLOUD_SERVERLESS_AUTHENTICATION_SERVICE_ACCOUNT: std.base64(std.manifestJsonEx(
GoogleCloudServerlessAuthenticationServiceAccount(dns_suffix), ''

View file

@ -62,6 +62,8 @@ func populateLogEvent(
return evt.Dur(string(field), dur)
case log.AccessLogFieldForwardedFor:
return evt.Str(string(field), entry.GetRequest().GetForwardedFor())
case log.AccessLogFieldIP:
return evt.Str(string(field), entry.GetCommonProperties().GetDownstreamRemoteAddress().GetSocketAddress().GetAddress())
case log.AccessLogFieldMethod:
return evt.Str(string(field), entry.GetRequest().GetRequestMethod().String())
case log.AccessLogFieldPath:

View file

@ -21,6 +21,13 @@ func Test_populateLogEvent(t *testing.T) {
entry := &envoy_data_accesslog_v3.HTTPAccessLogEntry{
CommonProperties: &envoy_data_accesslog_v3.AccessLogCommon{
DownstreamRemoteAddress: &envoy_config_core_v3.Address{
Address: &envoy_config_core_v3.Address_SocketAddress{
SocketAddress: &envoy_config_core_v3.SocketAddress{
Address: "127.0.0.1",
},
},
},
TimeToLastDownstreamTxByte: durationpb.New(time.Second * 3),
UpstreamCluster: "UPSTREAM-CLUSTER",
},
@ -47,6 +54,7 @@ func Test_populateLogEvent(t *testing.T) {
{log.AccessLogFieldAuthority, `{"authority":"AUTHORITY"}`},
{log.AccessLogFieldDuration, `{"duration":3000}`},
{log.AccessLogFieldForwardedFor, `{"forwarded-for":"FORWARDED-FOR"}`},
{log.AccessLogFieldIP, `{"ip":"127.0.0.1"}`},
{log.AccessLogFieldMethod, `{"method":"GET"}`},
{log.AccessLogFieldPath, `{"path":"https://www.example.com/some/path"}`},
{log.AccessLogFieldQuery, `{"query":"a=b"}`},

View file

@ -13,6 +13,7 @@ const (
AccessLogFieldAuthority AccessLogField = "authority"
AccessLogFieldDuration AccessLogField = "duration"
AccessLogFieldForwardedFor AccessLogField = "forwarded-for"
AccessLogFieldIP AccessLogField = "ip"
AccessLogFieldMethod AccessLogField = "method"
AccessLogFieldPath AccessLogField = "path"
AccessLogFieldQuery AccessLogField = "query"
@ -52,6 +53,7 @@ var accessLogFieldLookup = map[AccessLogField]struct{}{
AccessLogFieldAuthority: {},
AccessLogFieldDuration: {},
AccessLogFieldForwardedFor: {},
AccessLogFieldIP: {},
AccessLogFieldMethod: {},
AccessLogFieldPath: {},
AccessLogFieldQuery: {},

76
internal/retry/config.go Normal file
View file

@ -0,0 +1,76 @@
package retry
import (
"context"
"reflect"
"time"
"github.com/cenkalti/backoff/v4"
)
type config struct {
maxInterval time.Duration
watches []watch
backoff.BackOff
}
// watch is a helper struct to watch multiple channels
type watch struct {
name string
ch reflect.Value
fn func(context.Context) error
this bool
}
// Option configures the retry handler
type Option func(*config)
// WithWatch adds a watch to the retry handler
// that will be triggered when a value is received on the channel
// and the function will be called, also within a retry handler
func WithWatch[T any](name string, ch <-chan T, fn func(context.Context) error) Option {
return func(cfg *config) {
cfg.watches = append(cfg.watches, watch{name: name, ch: reflect.ValueOf(ch), fn: fn, this: false})
}
}
// WithMaxInterval sets the upper bound for the retry handler
func WithMaxInterval(d time.Duration) Option {
return func(cfg *config) {
cfg.maxInterval = d
}
}
func newConfig(opts ...Option) ([]watch, backoff.BackOff) {
cfg := new(config)
for _, opt := range []Option{
WithMaxInterval(time.Minute * 5),
} {
opt(cfg)
}
for _, opt := range opts {
opt(cfg)
}
for i, w := range cfg.watches {
cfg.watches[i].fn = withRetry(cfg, w)
}
bo := backoff.NewExponentialBackOff()
bo.MaxInterval = cfg.maxInterval
bo.MaxElapsedTime = 0
return cfg.watches, bo
}
func withRetry(cfg *config, w watch) func(context.Context) error {
if w.fn == nil {
return func(_ context.Context) error { return nil }
}
return func(ctx context.Context) error {
return Retry(ctx, w.name, w.fn, WithMaxInterval(cfg.maxInterval))
}
}

48
internal/retry/error.go Normal file
View file

@ -0,0 +1,48 @@
package retry
import (
"errors"
"fmt"
)
// TerminalError is an error that should not be retried
type TerminalError interface {
error
IsTerminal()
}
// terminalError is an error that should not be retried
type terminalError struct {
Err error
}
// Error implements error for terminalError
func (e *terminalError) Error() string {
return fmt.Sprintf("terminal error: %v", e.Err)
}
// Unwrap implements errors.Unwrap for terminalError
func (e *terminalError) Unwrap() error {
return e.Err
}
// Is implements errors.Is for terminalError
func (e *terminalError) Is(err error) bool {
//nolint:errorlint
_, ok := err.(*terminalError)
return ok
}
// IsTerminal implements TerminalError for terminalError
func (e *terminalError) IsTerminal() {}
// NewTerminalError creates a new terminal error that cannot be retried
func NewTerminalError(err error) error {
return &terminalError{Err: err}
}
// IsTerminalError returns true if the error is a terminal error
func IsTerminalError(err error) bool {
var te TerminalError
return errors.As(err, &te)
}

View file

@ -0,0 +1,29 @@
package retry_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/pomerium/pomerium/internal/retry"
)
type testError string
func (e testError) Error() string {
return string(e)
}
func (e testError) IsTerminal() {}
func TestError(t *testing.T) {
t.Run("local terminal error", func(t *testing.T) {
err := fmt.Errorf("wrap: %w", retry.NewTerminalError(fmt.Errorf("inner")))
require.True(t, retry.IsTerminalError(err))
})
t.Run("external terminal error", func(t *testing.T) {
err := fmt.Errorf("wrap: %w", testError("inner"))
require.True(t, retry.IsTerminalError(err))
})
}

139
internal/retry/retry.go Normal file
View file

@ -0,0 +1,139 @@
// Package retry provides a retry loop with exponential back-off
// while watching arbitrary signal channels for side effects.
package retry
import (
"context"
"fmt"
"reflect"
"time"
)
// Retry retries a function (with exponential back-off) until it succeeds.
// It additionally watches arbitrary channels and calls the handler function when a value is received.
// Handler functions are also retried with exponential back-off.
// If a terminal error is returned from the handler function, the retry loop is aborted.
// If the context is canceled, the retry loop is aborted.
func Retry(
ctx context.Context,
name string,
fn func(context.Context) error,
opts ...Option,
) error {
watches, backoff := newConfig(opts...)
ticker := time.NewTicker(backoff.NextBackOff())
defer ticker.Stop()
s := makeSelect(ctx, watches, name, ticker.C, fn)
restart:
for {
err := fn(ctx)
if err == nil {
return nil
}
if IsTerminalError(err) {
return err
}
backoff.Reset()
backoff:
for {
ticker.Reset(backoff.NextBackOff())
next, err := s.Exec(ctx)
switch next {
case nextRestart:
continue restart
case nextBackoff:
continue backoff
case nextExit:
return err
default:
panic("unreachable")
}
}
}
}
type selectCase struct {
watches []watch
cases []reflect.SelectCase
}
func makeSelect(
ctx context.Context,
watches []watch,
name string,
ch <-chan time.Time,
fn func(context.Context) error,
) *selectCase {
watches = append(watches,
watch{
name: "context",
fn: func(ctx context.Context) error {
// unreachable, the context handler will never be called
// as its channel can only be closed
return ctx.Err()
},
ch: reflect.ValueOf(ctx.Done()),
},
watch{
name: name,
fn: fn,
ch: reflect.ValueOf(ch),
this: true,
},
)
cases := make([]reflect.SelectCase, 0, len(watches))
for _, w := range watches {
cases = append(cases, reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: w.ch,
})
}
return &selectCase{
watches: watches,
cases: cases,
}
}
type next int
const (
nextRestart next = iota // try again from the beginning
nextBackoff // backoff and try again
nextExit // exit
)
func (s *selectCase) Exec(ctx context.Context) (next, error) {
chosen, _, ok := reflect.Select(s.cases)
if !ok {
return nextExit, fmt.Errorf("watch %s closed", s.watches[chosen].name)
}
w := s.watches[chosen]
err := w.fn(ctx)
if err != nil {
return onError(w, err)
}
if !w.this {
return nextRestart, nil
}
return nextExit, nil
}
func onError(w watch, err error) (next, error) {
if IsTerminalError(err) {
return nextExit, err
}
if w.this {
return nextBackoff, fmt.Errorf("retry %s failed: %w", w.name, err)
}
panic("unreachable, as watches are wrapped in retries and may only return terminal errors")
}

View file

@ -0,0 +1,124 @@
package retry_test
import (
"context"
"errors"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/pomerium/pomerium/internal/retry"
)
func TestRetry(t *testing.T) {
t.Parallel()
ctx := context.Background()
limit := retry.WithMaxInterval(time.Second * 5)
t.Run("no error", func(t *testing.T) {
t.Parallel()
err := retry.Retry(ctx, "test", func(_ context.Context) error {
return nil
}, limit)
require.NoError(t, err)
})
t.Run("eventually succeeds", func(t *testing.T) {
t.Parallel()
i := 0
err := retry.Retry(ctx, "test", func(_ context.Context) error {
if i++; i > 2 {
return nil
}
return fmt.Errorf("transient %d", i)
}, limit)
require.NoError(t, err)
})
t.Run("eventually fails", func(t *testing.T) {
t.Parallel()
i := 0
err := retry.Retry(ctx, "test", func(_ context.Context) error {
if i++; i > 2 {
return retry.NewTerminalError(errors.New("the end"))
}
return fmt.Errorf("transient %d", i)
})
require.Error(t, err)
})
t.Run("context canceled", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(ctx)
cancel()
err := retry.Retry(ctx, "test", func(_ context.Context) error {
return fmt.Errorf("retry")
})
require.Error(t, err)
})
t.Run("context canceled after retry", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(ctx)
t.Cleanup(cancel)
err := retry.Retry(ctx, "test", func(_ context.Context) error {
cancel()
return fmt.Errorf("retry")
})
require.Error(t, err)
})
t.Run("success after watch hook", func(t *testing.T) {
t.Parallel()
ch := make(chan struct{}, 1)
ch <- struct{}{}
ok := false
err := retry.Retry(ctx, "test", func(_ context.Context) error {
if ok {
return nil
}
return fmt.Errorf("retry")
}, retry.WithWatch("watch", ch, func(_ context.Context) error {
ok = true
return nil
}), limit)
require.NoError(t, err)
})
t.Run("success after watch hook retried", func(t *testing.T) {
t.Parallel()
ch := make(chan struct{}, 1)
ch <- struct{}{}
ok := false
i := 0
err := retry.Retry(ctx, "test", func(_ context.Context) error {
if ok {
return nil
}
return fmt.Errorf("retry test")
}, retry.WithWatch("watch", ch, func(_ context.Context) error {
if i++; i > 1 {
ok = true
return nil
}
return fmt.Errorf("retry watch")
}), limit)
require.NoError(t, err)
})
t.Run("watch hook fails", func(t *testing.T) {
t.Parallel()
ch := make(chan struct{}, 1)
ch <- struct{}{}
err := retry.Retry(ctx, "test", func(_ context.Context) error {
return fmt.Errorf("retry")
}, retry.WithWatch("watch", ch, func(_ context.Context) error {
return retry.NewTerminalError(fmt.Errorf("watch"))
}), limit)
require.Error(t, err)
})
}

View file

@ -4,7 +4,6 @@ import (
"crypto/ecdsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/base64"
"encoding/pem"
"errors"
@ -16,7 +15,6 @@ import (
)
const (
crlPemType = "X509 CRL"
maxCertFileSize = 1 << 16
)
@ -41,43 +39,28 @@ func CertificateFromFile(certFile, keyFile string) (*tls.Certificate, error) {
return &cert, err
}
// CRLFromBase64 parses a certificate revocation list from a base64 encoded blob.
func CRLFromBase64(rawCRL string) (*pkix.CertificateList, error) {
bs, err := base64.StdEncoding.DecodeString(rawCRL)
if err != nil {
return nil, fmt.Errorf("cryptutil: failed to decode base64 crl: %w", err)
}
return DecodeCRL(bs)
}
// CRLFromFile parses a certificate revocation list from a file.
func CRLFromFile(fileName string) (*pkix.CertificateList, error) {
bs, err := os.ReadFile(fileName)
if err != nil {
return nil, fmt.Errorf("cryptutil: failed to read crl file (%s): %w", fileName, err)
}
return DecodeCRL(bs)
}
// DecodeCRL decodes a PEM-encoded certificate revocation list.
func DecodeCRL(encodedCRL []byte) (*pkix.CertificateList, error) {
data := encodedCRL
for len(data) > 0 {
// ParseCRLs parses PEM-encoded certificate revocation lists, returning a map
// of the parsed CRLs keyed by the raw issuer name.
func ParseCRLs(crl []byte) (map[string]*x509.RevocationList, error) {
m := make(map[string]*x509.RevocationList)
for {
var block *pem.Block
block, data = pem.Decode(data)
block, crl = pem.Decode(crl)
if block == nil {
break
}
if block.Type == crlPemType {
lst, err := x509.ParseDERCRL(block.Bytes)
if err != nil {
return nil, fmt.Errorf("cryptutil: failed to parse crl: %w", err)
if len(crl) > 0 {
return nil, errors.New("cryptutil: non-PEM data in CRL bundle")
}
return lst, nil
return m, nil
}
if block.Type != "X509 CRL" {
continue
}
l, err := x509.ParseRevocationList(block.Bytes)
if err != nil {
return nil, fmt.Errorf("cryptutil: failed to parse crl: %w", err)
}
m[string(l.RawIssuer)] = l
}
return nil, fmt.Errorf("cryptutil: invalid crl, no %s block found", crlPemType)
}
// DecodePublicKey decodes a PEM-encoded ECDSA public key.

View file

@ -106,29 +106,18 @@ func TestCertificateFromFile(t *testing.T) {
_ = listener
}
func TestCRLFromBase64(t *testing.T) {
bs := base64.StdEncoding.EncodeToString([]byte(pemCRL))
lst, err := CRLFromBase64(bs)
func TestParseCRLs(t *testing.T) {
crls, err := ParseCRLs([]byte(pemCRL))
assert.NoError(t, err)
assert.NotNil(t, lst)
}
func TestCRLFromFile(t *testing.T) {
lst, err := CRLFromFile("testdata/example-crl.pem")
assert.NoError(t, err)
assert.NotNil(t, lst)
}
func TestDecodeCRL(t *testing.T) {
lst, err := DecodeCRL([]byte(pemCRL))
assert.NoError(t, err)
assert.NotNil(t, lst)
assert.Equal(t, 1, len(crls))
crl := crls["0l1\x1a0\x18\x06\x03U\x04\n\x13\x11RSA Security Inc.1\x1e0\x1c\x06\x03U\x04\x03\x13\x15RSA Public Root CA v11.0,\x06\t*\x86H\x86\xf7\r\x01\t\x01\x16\x1frsakeonrootsign@rsasecurity.com"]
assert.NotNil(t, crl)
t.Run("der", func(t *testing.T) {
bs, _ := base64.StdEncoding.DecodeString(derCRLBase64)
lst, err := DecodeCRL(bs)
crls, err := ParseCRLs(bs)
assert.Error(t, err, "should not allow DER encoded CRL")
assert.Nil(t, lst)
assert.Nil(t, crls)
})
}

View file

@ -1,13 +0,0 @@
-----BEGIN X509 CRL-----
MIIB9jCCAV8CAQEwDQYJKoZIhvcNAQEFBQAwbDEaMBgGA1UEChMRUlNBIFNlY3Vy
aXR5IEluYy4xHjAcBgNVBAMTFVJTQSBQdWJsaWMgUm9vdCBDQSB2MTEuMCwGCSqG
SIb3DQEJARYfcnNha2VvbnJvb3RzaWduQHJzYXNlY3VyaXR5LmNvbRcNMTEwMjIz
MTkyODMwWhcNMTEwODIyMTkyODMwWjCBjDBKAhEArDqoh9FHJHXT7OPguun4+BcN
MDkxMTAyMTQyNzA5WjAmMAoGA1UdFQQDCgEJMBgGA1UdGAQRGA8yMDA5MTEwMjE0
MjQ1NVowPgIRALGznZ095PB5aAOLPg57fMMXDTAyMTAyMzE0NTAxNFowGjAYBgNV
HRgEERgPMjAwMjEwMjMxNDUwMTRaoDAwLjAfBgNVHSMEGDAWgBT1TDF6UQM/LNeL
l5lvqHGQq3g9mzALBgNVHRQEBAICAIQwDQYJKoZIhvcNAQEFBQADgYEAFU5As6Mz
q5PRsifaobQPGh1aJLyC+Ms5Agc0bWyA3GAdxur5SpPZeRWCBjiP/MEHBWJClBHP
GRcq5yId3EjDkaEyxRa+i67LzvhI6c29Ee6K9pSYwji/7RUhmmnPrXtTxlL0lrLr
mQQJ6xhDRa5G3QA4CmUdsHNvbrzgmCYpvVE=
-----END X509 CRL-----

View file

@ -25,6 +25,58 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type MtlsEnforcementMode int32
const (
MtlsEnforcementMode_UNKNOWN MtlsEnforcementMode = 0
MtlsEnforcementMode_POLICY MtlsEnforcementMode = 1
MtlsEnforcementMode_POLICY_WITH_DEFAULT_DENY MtlsEnforcementMode = 2
MtlsEnforcementMode_REJECT_CONNECTION MtlsEnforcementMode = 3
)
// Enum value maps for MtlsEnforcementMode.
var (
MtlsEnforcementMode_name = map[int32]string{
0: "UNKNOWN",
1: "POLICY",
2: "POLICY_WITH_DEFAULT_DENY",
3: "REJECT_CONNECTION",
}
MtlsEnforcementMode_value = map[string]int32{
"UNKNOWN": 0,
"POLICY": 1,
"POLICY_WITH_DEFAULT_DENY": 2,
"REJECT_CONNECTION": 3,
}
)
func (x MtlsEnforcementMode) Enum() *MtlsEnforcementMode {
p := new(MtlsEnforcementMode)
*p = x
return p
}
func (x MtlsEnforcementMode) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (MtlsEnforcementMode) Descriptor() protoreflect.EnumDescriptor {
return file_config_proto_enumTypes[0].Descriptor()
}
func (MtlsEnforcementMode) Type() protoreflect.EnumType {
return &file_config_proto_enumTypes[0]
}
func (x MtlsEnforcementMode) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use MtlsEnforcementMode.Descriptor instead.
func (MtlsEnforcementMode) EnumDescriptor() ([]byte, []int) {
return file_config_proto_rawDescGZIP(), []int{0}
}
type Route_AuthorizationHeaderMode int32
const (
@ -58,11 +110,11 @@ func (x Route_AuthorizationHeaderMode) String() string {
}
func (Route_AuthorizationHeaderMode) Descriptor() protoreflect.EnumDescriptor {
return file_config_proto_enumTypes[0].Descriptor()
return file_config_proto_enumTypes[1].Descriptor()
}
func (Route_AuthorizationHeaderMode) Type() protoreflect.EnumType {
return &file_config_proto_enumTypes[0]
return &file_config_proto_enumTypes[1]
}
func (x Route_AuthorizationHeaderMode) Number() protoreflect.EnumNumber {
@ -903,6 +955,7 @@ func (x *Policy) GetRemediation() string {
return ""
}
// Next ID: 117.
type Settings struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -969,13 +1022,14 @@ type Settings struct {
GrpcClientTimeout *durationpb.Duration `protobuf:"bytes,99,opt,name=grpc_client_timeout,json=grpcClientTimeout,proto3,oneof" json:"grpc_client_timeout,omitempty"`
GrpcClientDnsRoundrobin *bool `protobuf:"varint,100,opt,name=grpc_client_dns_roundrobin,json=grpcClientDnsRoundrobin,proto3,oneof" json:"grpc_client_dns_roundrobin,omitempty"`
// optional string forward_auth_url = 50;
DatabrokerServiceUrls []string `protobuf:"bytes,52,rep,name=databroker_service_urls,json=databrokerServiceUrls,proto3" json:"databroker_service_urls,omitempty"`
DatabrokerInternalServiceUrl *string `protobuf:"bytes,84,opt,name=databroker_internal_service_url,json=databrokerInternalServiceUrl,proto3,oneof" json:"databroker_internal_service_url,omitempty"`
DatabrokerStorageType *string `protobuf:"bytes,101,opt,name=databroker_storage_type,json=databrokerStorageType,proto3,oneof" json:"databroker_storage_type,omitempty"`
DatabrokerStorageConnectionString *string `protobuf:"bytes,102,opt,name=databroker_storage_connection_string,json=databrokerStorageConnectionString,proto3,oneof" json:"databroker_storage_connection_string,omitempty"`
DatabrokerStorageTlsSkipVerify *bool `protobuf:"varint,106,opt,name=databroker_storage_tls_skip_verify,json=databrokerStorageTlsSkipVerify,proto3,oneof" json:"databroker_storage_tls_skip_verify,omitempty"`
ClientCa *string `protobuf:"bytes,53,opt,name=client_ca,json=clientCa,proto3,oneof" json:"client_ca,omitempty"`
ClientCrl *string `protobuf:"bytes,74,opt,name=client_crl,json=clientCrl,proto3,oneof" json:"client_crl,omitempty"`
DatabrokerServiceUrls []string `protobuf:"bytes,52,rep,name=databroker_service_urls,json=databrokerServiceUrls,proto3" json:"databroker_service_urls,omitempty"`
DatabrokerInternalServiceUrl *string `protobuf:"bytes,84,opt,name=databroker_internal_service_url,json=databrokerInternalServiceUrl,proto3,oneof" json:"databroker_internal_service_url,omitempty"`
DatabrokerStorageType *string `protobuf:"bytes,101,opt,name=databroker_storage_type,json=databrokerStorageType,proto3,oneof" json:"databroker_storage_type,omitempty"`
DatabrokerStorageConnectionString *string `protobuf:"bytes,102,opt,name=databroker_storage_connection_string,json=databrokerStorageConnectionString,proto3,oneof" json:"databroker_storage_connection_string,omitempty"`
DatabrokerStorageTlsSkipVerify *bool `protobuf:"varint,106,opt,name=databroker_storage_tls_skip_verify,json=databrokerStorageTlsSkipVerify,proto3,oneof" json:"databroker_storage_tls_skip_verify,omitempty"`
DownstreamMtls *DownstreamMtlsSettings `protobuf:"bytes,116,opt,name=downstream_mtls,json=downstreamMtls,proto3,oneof" json:"downstream_mtls,omitempty"`
// optional string client_ca = 53;
// optional string client_crl = 74;
GoogleCloudServerlessAuthenticationServiceAccount *string `protobuf:"bytes,55,opt,name=google_cloud_serverless_authentication_service_account,json=googleCloudServerlessAuthenticationServiceAccount,proto3,oneof" json:"google_cloud_serverless_authentication_service_account,omitempty"`
UseProxyProtocol *bool `protobuf:"varint,107,opt,name=use_proxy_protocol,json=useProxyProtocol,proto3,oneof" json:"use_proxy_protocol,omitempty"`
Autocert *bool `protobuf:"varint,56,opt,name=autocert,proto3,oneof" json:"autocert,omitempty"`
@ -1465,18 +1519,11 @@ func (x *Settings) GetDatabrokerStorageTlsSkipVerify() bool {
return false
}
func (x *Settings) GetClientCa() string {
if x != nil && x.ClientCa != nil {
return *x.ClientCa
func (x *Settings) GetDownstreamMtls() *DownstreamMtlsSettings {
if x != nil {
return x.DownstreamMtls
}
return ""
}
func (x *Settings) GetClientCrl() string {
if x != nil && x.ClientCrl != nil {
return *x.ClientCrl
}
return ""
return nil
}
func (x *Settings) GetGoogleCloudServerlessAuthenticationServiceAccount() string {
@ -1675,6 +1722,69 @@ func (x *Settings) GetErrorMessageFirstParagraph() string {
return ""
}
type DownstreamMtlsSettings struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Ca *string `protobuf:"bytes,1,opt,name=ca,proto3,oneof" json:"ca,omitempty"`
Crl *string `protobuf:"bytes,2,opt,name=crl,proto3,oneof" json:"crl,omitempty"`
Enforcement *MtlsEnforcementMode `protobuf:"varint,3,opt,name=enforcement,proto3,enum=pomerium.config.MtlsEnforcementMode,oneof" json:"enforcement,omitempty"`
}
func (x *DownstreamMtlsSettings) Reset() {
*x = DownstreamMtlsSettings{}
if protoimpl.UnsafeEnabled {
mi := &file_config_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DownstreamMtlsSettings) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DownstreamMtlsSettings) ProtoMessage() {}
func (x *DownstreamMtlsSettings) ProtoReflect() protoreflect.Message {
mi := &file_config_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DownstreamMtlsSettings.ProtoReflect.Descriptor instead.
func (*DownstreamMtlsSettings) Descriptor() ([]byte, []int) {
return file_config_proto_rawDescGZIP(), []int{6}
}
func (x *DownstreamMtlsSettings) GetCa() string {
if x != nil && x.Ca != nil {
return *x.Ca
}
return ""
}
func (x *DownstreamMtlsSettings) GetCrl() string {
if x != nil && x.Crl != nil {
return *x.Crl
}
return ""
}
func (x *DownstreamMtlsSettings) GetEnforcement() MtlsEnforcementMode {
if x != nil && x.Enforcement != nil {
return *x.Enforcement
}
return MtlsEnforcementMode_UNKNOWN
}
type Settings_Certificate struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -1687,7 +1797,7 @@ type Settings_Certificate struct {
func (x *Settings_Certificate) Reset() {
*x = Settings_Certificate{}
if protoimpl.UnsafeEnabled {
mi := &file_config_proto_msgTypes[10]
mi := &file_config_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -1700,7 +1810,7 @@ func (x *Settings_Certificate) String() string {
func (*Settings_Certificate) ProtoMessage() {}
func (x *Settings_Certificate) ProtoReflect() protoreflect.Message {
mi := &file_config_proto_msgTypes[10]
mi := &file_config_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -1741,7 +1851,7 @@ type Settings_StringList struct {
func (x *Settings_StringList) Reset() {
*x = Settings_StringList{}
if protoimpl.UnsafeEnabled {
mi := &file_config_proto_msgTypes[11]
mi := &file_config_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -1754,7 +1864,7 @@ func (x *Settings_StringList) String() string {
func (*Settings_StringList) ProtoMessage() {}
func (x *Settings_StringList) ProtoReflect() protoreflect.Message {
mi := &file_config_proto_msgTypes[11]
mi := &file_config_proto_msgTypes[12]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -2074,8 +2184,8 @@ var file_config_proto_rawDesc = []byte{
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf9,
0x3a, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2c, 0x0a, 0x0f, 0x69,
0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x81,
0x3b, 0x0a, 0x08, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2c, 0x0a, 0x0f, 0x69,
0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x47,
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x64, 0x65, 0x62,
@ -2297,256 +2407,274 @@ var file_config_proto_rawDesc = []byte{
0x65, 0x5f, 0x74, 0x6c, 0x73, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66,
0x79, 0x18, 0x6a, 0x20, 0x01, 0x28, 0x08, 0x48, 0x35, 0x52, 0x1e, 0x64, 0x61, 0x74, 0x61, 0x62,
0x72, 0x6f, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x54, 0x6c, 0x73, 0x53,
0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x18, 0x35, 0x20, 0x01, 0x28, 0x09, 0x48,
0x36, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x61, 0x88, 0x01, 0x01, 0x12, 0x22,
0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x6c, 0x18, 0x4a, 0x20, 0x01,
0x28, 0x09, 0x48, 0x37, 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x6c, 0x88,
0x01, 0x01, 0x12, 0x76, 0x0a, 0x36, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x6f,
0x75, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x61, 0x75,
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x37, 0x20, 0x01,
0x28, 0x09, 0x48, 0x38, 0x52, 0x31, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x43, 0x6c, 0x6f, 0x75,
0x64, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65,
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x12, 0x75, 0x73,
0x65, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x18, 0x6b, 0x20, 0x01, 0x28, 0x08, 0x48, 0x39, 0x52, 0x10, 0x75, 0x73, 0x65, 0x50, 0x72, 0x6f,
0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a,
0x08, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x38, 0x20, 0x01, 0x28, 0x08, 0x48,
0x3a, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x88, 0x01, 0x01, 0x12, 0x24,
0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x61, 0x18, 0x4c, 0x20,
0x01, 0x28, 0x09, 0x48, 0x3b, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x43,
0x61, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x4d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x3c, 0x52, 0x0d,
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x88, 0x01, 0x01,
0x12, 0x35, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x75, 0x73, 0x65,
0x5f, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x18, 0x39, 0x20, 0x01, 0x28, 0x08, 0x48, 0x3d,
0x52, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x53, 0x74, 0x61,
0x67, 0x69, 0x6e, 0x67, 0x88, 0x01, 0x01, 0x12, 0x32, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x4e,
0x20, 0x01, 0x28, 0x09, 0x48, 0x3e, 0x52, 0x10, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x45, 0x61, 0x62, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x34, 0x0a, 0x14, 0x61,
0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6d, 0x61, 0x63, 0x5f,
0x6b, 0x65, 0x79, 0x18, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x3f, 0x52, 0x11, 0x61, 0x75, 0x74,
0x6f, 0x63, 0x65, 0x72, 0x74, 0x45, 0x61, 0x62, 0x4d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x88, 0x01,
0x01, 0x12, 0x35, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6d, 0x75,
0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x08, 0x48,
0x40, 0x52, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x4d, 0x75, 0x73, 0x74, 0x53,
0x74, 0x61, 0x70, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x41,
0x52, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x44, 0x69, 0x72, 0x88, 0x01, 0x01,
0x12, 0x33, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x72, 0x75,
0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x48, 0x42, 0x52,
0x11, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64,
0x43, 0x61, 0x88, 0x01, 0x01, 0x12, 0x2b, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x78, 0x66,
0x66, 0x5f, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x08, 0x48, 0x43,
0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x58, 0x66, 0x66, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x88,
0x01, 0x01, 0x12, 0x34, 0x0a, 0x14, 0x78, 0x66, 0x66, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x74, 0x72,
0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0d,
0x48, 0x44, 0x52, 0x11, 0x78, 0x66, 0x66, 0x4e, 0x75, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65,
0x64, 0x48, 0x6f, 0x70, 0x73, 0x88, 0x01, 0x01, 0x12, 0x41, 0x0a, 0x1b, 0x65, 0x6e, 0x76, 0x6f,
0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c,
0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x6c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x45, 0x52,
0x17, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x18, 0x65,
0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x6d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x46, 0x52,
0x15, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x13, 0x65, 0x6e, 0x76,
0x6f, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x18, 0x6e, 0x20, 0x01, 0x28, 0x09, 0x48, 0x47, 0x52, 0x11, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x41,
0x64, 0x6d, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x4b,
0x0a, 0x20, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x18, 0x6f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x48, 0x52, 0x1c, 0x65, 0x6e, 0x76, 0x6f,
0x79, 0x42, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x40, 0x0a, 0x1a, 0x65,
0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x5f, 0x66, 0x72, 0x65, 0x65, 0x62, 0x69, 0x6e, 0x64, 0x18, 0x70, 0x20, 0x01, 0x28, 0x09, 0x48,
0x49, 0x52, 0x17, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x42, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x46, 0x72, 0x65, 0x65, 0x62, 0x69, 0x6e, 0x64, 0x88, 0x01, 0x01, 0x12, 0x53, 0x0a,
0x26, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72, 0x65,
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x77, 0x68,
0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x44, 0x20, 0x03, 0x28, 0x09, 0x52, 0x23, 0x70,
0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x52, 0x65, 0x64, 0x69, 0x72,
0x65, 0x63, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69,
0x73, 0x74, 0x12, 0x80, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f, 0x74, 0x79, 0x70,
0x65, 0x18, 0x49, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x5c, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x2e,
0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65,
0x72, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x5f,
0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67,
0x65, 0x72, 0x2e, 0x76, 0x33, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64, 0x65,
0x63, 0x54, 0x79, 0x70, 0x65, 0x48, 0x4a, 0x52, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x54, 0x79,
0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x48, 0x0a, 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x6b,
0x65, 0x79, 0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72,
0x69, 0x75, 0x6d, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79,
0x48, 0x4b, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01, 0x12,
0x28, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72,
0x18, 0x55, 0x20, 0x01, 0x28, 0x09, 0x48, 0x4c, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72,
0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x73, 0x65, 0x63,
0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x56, 0x20, 0x01,
0x28, 0x09, 0x48, 0x4d, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x43,
0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x16, 0x64, 0x61, 0x72, 0x6b, 0x6d,
0x6f, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f,
0x72, 0x18, 0x57, 0x20, 0x01, 0x28, 0x09, 0x48, 0x4e, 0x52, 0x14, 0x64, 0x61, 0x72, 0x6b, 0x6d,
0x6f, 0x64, 0x65, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88,
0x01, 0x01, 0x12, 0x3d, 0x0a, 0x18, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x73,
0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x58,
0x20, 0x01, 0x28, 0x09, 0x48, 0x4f, 0x52, 0x16, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65,
0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01,
0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x59, 0x20,
0x01, 0x28, 0x09, 0x48, 0x50, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x6c, 0x88, 0x01,
0x01, 0x12, 0x24, 0x0a, 0x0b, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c,
0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x51, 0x52, 0x0a, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f,
0x6e, 0x55, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x46, 0x0a, 0x1d, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x70,
0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x09, 0x48, 0x52,
0x52, 0x1a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x46, 0x69,
0x72, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x88, 0x01, 0x01, 0x1a,
0x49, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1d,
0x0a, 0x0a, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x09, 0x63, 0x65, 0x72, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1b, 0x0a,
0x09, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x08, 0x6b, 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x1a, 0x24, 0x0a, 0x0a, 0x53, 0x74,
0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73,
0x1a, 0x40, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x4a, 0x77, 0x74,
0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x12,
0x0a, 0x10, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x69, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x42, 0x0c, 0x0a, 0x0a,
0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x61,
0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73,
0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x6c,
0x6f, 0x67, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x10, 0x0a,
0x0e, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42,
0x0b, 0x0a, 0x09, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x0a, 0x0a, 0x08,
0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x69, 0x6e, 0x73,
0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x14, 0x0a, 0x12,
0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x66, 0x61, 0x6d, 0x69,
0x6c, 0x79, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x64, 0x69,
0x72, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74, 0x69,
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x42, 0x0f, 0x0a, 0x0d,
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x69, 0x64, 0x6c, 0x65, 0x42, 0x1b, 0x0a,
0x19, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x24, 0x0a, 0x22, 0x5f, 0x61,
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c,
0x42, 0x17, 0x0a, 0x15, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x6f, 0x75, 0x74, 0x5f, 0x72, 0x65, 0x64,
0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x61, 0x75,
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62,
0x61, 0x63, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x6f, 0x6f,
0x6b, 0x69, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f,
0x6b, 0x69, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63,
0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x10, 0x0a, 0x0e,
0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x13,
0x0a, 0x11, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x6f,
0x6e, 0x6c, 0x79, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x65,
0x78, 0x70, 0x69, 0x72, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65,
0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x69, 0x74, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x69,
0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x14, 0x0a, 0x12,
0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72,
0x65, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x72, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x21, 0x0a, 0x1f, 0x5f, 0x61, 0x75, 0x74,
0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1c, 0x0a, 0x1a, 0x5f,
0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x63, 0x65,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
0x69, 0x74, 0x79, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x5f, 0x74,
0x6c, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6b,
0x65, 0x79, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x75,
0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x42,
0x12, 0x0a, 0x10, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f,
0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x6d,
0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x63,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x74, 0x72, 0x61,
0x63, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x16, 0x0a,
0x14, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65,
0x5f, 0x72, 0x61, 0x74, 0x65, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e,
0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x64, 0x6f, 0x67, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x42, 0x24, 0x0a, 0x22, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61,
0x65, 0x67, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x65,
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x74, 0x72, 0x61, 0x63,
0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74,
0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x74, 0x72,
0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x7a, 0x69, 0x70, 0x6b, 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x64,
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x67, 0x72, 0x70, 0x63, 0x5f,
0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x67, 0x72, 0x70,
0x63, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x72, 0x6f, 0x62, 0x69, 0x6e, 0x42,
0x22, 0x0a, 0x20, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x75, 0x72, 0x6c, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b,
0x65, 0x72, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42,
0x27, 0x0a, 0x25, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x73,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x42, 0x25, 0x0a, 0x23, 0x5f, 0x64, 0x61, 0x74,
0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f,
0x74, 0x6c, 0x73, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x42,
0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x42, 0x0d, 0x0a,
0x0b, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x72, 0x6c, 0x42, 0x39, 0x0a, 0x37,
0x5f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f,
0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x75, 0x73, 0x65, 0x5f,
0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x42, 0x0b,
0x0a, 0x09, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x42, 0x0e, 0x0a, 0x0c, 0x5f,
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x61, 0x42, 0x11, 0x0a, 0x0f, 0x5f,
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x42, 0x17,
0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x5f,
0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, 0x75, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x42,
0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62,
0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74,
0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6d, 0x75, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c,
0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64,
0x69, 0x72, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f,
0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73,
0x6b, 0x69, 0x70, 0x5f, 0x78, 0x66, 0x66, 0x5f, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x42, 0x17,
0x0a, 0x15, 0x5f, 0x78, 0x66, 0x66, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74,
0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x65, 0x6e, 0x76, 0x6f,
0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c,
0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x65, 0x6e, 0x76, 0x6f,
0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f,
0x70, 0x61, 0x74, 0x68, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x61,
0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x23, 0x0a, 0x21,
0x5f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64,
0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x62, 0x69, 0x6e, 0x64,
0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42,
0x0c, 0x0a, 0x0a, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x10, 0x0a,
0x0e, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42,
0x12, 0x0a, 0x10, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f,
0x6c, 0x6f, 0x72, 0x42, 0x19, 0x0a, 0x17, 0x5f, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65,
0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x1b,
0x0a, 0x19, 0x5f, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f,
0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f,
0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x66, 0x61, 0x76,
0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74,
0x5f, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69,
0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x88, 0x01, 0x01, 0x12, 0x55, 0x0a, 0x0f,
0x64, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x74, 0x6c, 0x73, 0x18,
0x74, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d,
0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65,
0x61, 0x6d, 0x4d, 0x74, 0x6c, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x48, 0x36,
0x52, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x74, 0x6c, 0x73,
0x88, 0x01, 0x01, 0x12, 0x76, 0x0a, 0x36, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x63, 0x6c,
0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x61,
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x37, 0x20,
0x01, 0x28, 0x09, 0x48, 0x37, 0x52, 0x31, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x43, 0x6c, 0x6f,
0x75, 0x64, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68,
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x12, 0x75,
0x73, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x18, 0x6b, 0x20, 0x01, 0x28, 0x08, 0x48, 0x38, 0x52, 0x10, 0x75, 0x73, 0x65, 0x50, 0x72,
0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x1f,
0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x38, 0x20, 0x01, 0x28, 0x08,
0x48, 0x39, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x88, 0x01, 0x01, 0x12,
0x24, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x61, 0x18, 0x4c,
0x20, 0x01, 0x28, 0x09, 0x48, 0x3a, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x43, 0x61, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
0x74, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x4d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x3b, 0x52,
0x0d, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x88, 0x01,
0x01, 0x12, 0x35, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x75, 0x73,
0x65, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x18, 0x39, 0x20, 0x01, 0x28, 0x08, 0x48,
0x3c, 0x52, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x55, 0x73, 0x65, 0x53, 0x74,
0x61, 0x67, 0x69, 0x6e, 0x67, 0x88, 0x01, 0x01, 0x12, 0x32, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18,
0x4e, 0x20, 0x01, 0x28, 0x09, 0x48, 0x3d, 0x52, 0x10, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
0x74, 0x45, 0x61, 0x62, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x34, 0x0a, 0x14,
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6d, 0x61, 0x63,
0x5f, 0x6b, 0x65, 0x79, 0x18, 0x4f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x3e, 0x52, 0x11, 0x61, 0x75,
0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x45, 0x61, 0x62, 0x4d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x88,
0x01, 0x01, 0x12, 0x35, 0x0a, 0x14, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6d,
0x75, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x08,
0x48, 0x3f, 0x52, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x4d, 0x75, 0x73, 0x74,
0x53, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x61, 0x75, 0x74,
0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x09, 0x48,
0x40, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x44, 0x69, 0x72, 0x88, 0x01,
0x01, 0x12, 0x33, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x72,
0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x61, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x48, 0x41,
0x52, 0x11, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65,
0x64, 0x43, 0x61, 0x88, 0x01, 0x01, 0x12, 0x2b, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x78,
0x66, 0x66, 0x5f, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x08, 0x48,
0x42, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x58, 0x66, 0x66, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64,
0x88, 0x01, 0x01, 0x12, 0x34, 0x0a, 0x14, 0x78, 0x66, 0x66, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, 0x74,
0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x46, 0x20, 0x01, 0x28,
0x0d, 0x48, 0x43, 0x52, 0x11, 0x78, 0x66, 0x66, 0x4e, 0x75, 0x6d, 0x54, 0x72, 0x75, 0x73, 0x74,
0x65, 0x64, 0x48, 0x6f, 0x70, 0x73, 0x88, 0x01, 0x01, 0x12, 0x41, 0x0a, 0x1b, 0x65, 0x6e, 0x76,
0x6f, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f,
0x6c, 0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x6c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x44,
0x52, 0x17, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65,
0x73, 0x73, 0x4c, 0x6f, 0x67, 0x50, 0x61, 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x18,
0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x6d, 0x20, 0x01, 0x28, 0x09, 0x48, 0x45,
0x52, 0x15, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x13, 0x65, 0x6e,
0x76, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x18, 0x6e, 0x20, 0x01, 0x28, 0x09, 0x48, 0x46, 0x52, 0x11, 0x65, 0x6e, 0x76, 0x6f, 0x79,
0x41, 0x64, 0x6d, 0x69, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12,
0x4b, 0x0a, 0x20, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x18, 0x6f, 0x20, 0x01, 0x28, 0x09, 0x48, 0x47, 0x52, 0x1c, 0x65, 0x6e, 0x76,
0x6f, 0x79, 0x42, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x12, 0x40, 0x0a, 0x1a,
0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x62, 0x69, 0x6e, 0x64, 0x18, 0x70, 0x20, 0x01, 0x28, 0x09,
0x48, 0x48, 0x52, 0x17, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x42, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x46, 0x72, 0x65, 0x65, 0x62, 0x69, 0x6e, 0x64, 0x88, 0x01, 0x01, 0x12, 0x53,
0x0a, 0x26, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x72,
0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x77,
0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x44, 0x20, 0x03, 0x28, 0x09, 0x52, 0x23,
0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x52, 0x65, 0x64, 0x69,
0x72, 0x65, 0x63, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c,
0x69, 0x73, 0x74, 0x12, 0x80, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f, 0x74, 0x79,
0x70, 0x65, 0x18, 0x49, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x5c, 0x2e, 0x65, 0x6e, 0x76, 0x6f, 0x79,
0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74,
0x65, 0x72, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x68, 0x74, 0x74, 0x70,
0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x6e, 0x61,
0x67, 0x65, 0x72, 0x2e, 0x76, 0x33, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64,
0x65, 0x63, 0x54, 0x79, 0x70, 0x65, 0x48, 0x49, 0x52, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x54,
0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x48, 0x0a, 0x09, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f,
0x6b, 0x65, 0x79, 0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6d, 0x65,
0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65,
0x79, 0x48, 0x4a, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x88, 0x01, 0x01,
0x12, 0x28, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f,
0x72, 0x18, 0x55, 0x20, 0x01, 0x28, 0x09, 0x48, 0x4b, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x6d, 0x61,
0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x73, 0x65,
0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x56, 0x20,
0x01, 0x28, 0x09, 0x48, 0x4c, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79,
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88, 0x01, 0x01, 0x12, 0x39, 0x0a, 0x16, 0x64, 0x61, 0x72, 0x6b,
0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c,
0x6f, 0x72, 0x18, 0x57, 0x20, 0x01, 0x28, 0x09, 0x48, 0x4d, 0x52, 0x14, 0x64, 0x61, 0x72, 0x6b,
0x6d, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x18, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f,
0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18,
0x58, 0x20, 0x01, 0x28, 0x09, 0x48, 0x4e, 0x52, 0x16, 0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64,
0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x88,
0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x59,
0x20, 0x01, 0x28, 0x09, 0x48, 0x4f, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x6f, 0x55, 0x72, 0x6c, 0x88,
0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72,
0x6c, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x50, 0x52, 0x0a, 0x66, 0x61, 0x76, 0x69, 0x63,
0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x46, 0x0a, 0x1d, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f,
0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x09, 0x48,
0x51, 0x52, 0x1a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x46,
0x69, 0x72, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x88, 0x01, 0x01,
0x1a, 0x49, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12,
0x1d, 0x0a, 0x0a, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x65, 0x72, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1b,
0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x1a, 0x24, 0x0a, 0x0a, 0x53,
0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x73, 0x1a, 0x40, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x4a, 0x77,
0x74, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42,
0x12, 0x0a, 0x10, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x5f, 0x69, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x42, 0x0c, 0x0a,
0x0a, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x14, 0x0a, 0x12, 0x5f,
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64,
0x73, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f,
0x6c, 0x6f, 0x67, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x70,
0x72, 0x6f, 0x78, 0x79, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x10,
0x0a, 0x0e, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74,
0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x0a, 0x0a,
0x08, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x69, 0x6e,
0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x14, 0x0a,
0x12, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x5f, 0x66, 0x61, 0x6d,
0x69, 0x6c, 0x79, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x64,
0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x42, 0x10, 0x0a, 0x0e, 0x5f,
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x42, 0x0f, 0x0a,
0x0d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x69, 0x64, 0x6c, 0x65, 0x42, 0x1b,
0x0a, 0x19, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x24, 0x0a, 0x22, 0x5f,
0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72,
0x6c, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x6f, 0x75, 0x74, 0x5f, 0x72, 0x65,
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x61,
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x6f,
0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f,
0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x10, 0x0a, 0x0e, 0x5f,
0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x10, 0x0a,
0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42,
0x13, 0x0a, 0x11, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x5f,
0x6f, 0x6e, 0x6c, 0x79, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x5f,
0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x63, 0x6f, 0x6f, 0x6b, 0x69,
0x65, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x69, 0x74, 0x65, 0x42, 0x10, 0x0a, 0x0e, 0x5f,
0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x14, 0x0a,
0x12, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63,
0x72, 0x65, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69, 0x64, 0x70, 0x5f, 0x70, 0x72, 0x6f,
0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x21, 0x0a, 0x1f, 0x5f, 0x61, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1c, 0x0a, 0x1a,
0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x63,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f,
0x72, 0x69, 0x74, 0x79, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x5f,
0x74, 0x6c, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f,
0x6b, 0x65, 0x79, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f,
0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x42, 0x16, 0x0a, 0x14, 0x5f,
0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x74, 0x72,
0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x42, 0x16,
0x0a, 0x14, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c,
0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69,
0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x64, 0x6f, 0x67, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x42, 0x24, 0x0a, 0x22, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x6a,
0x61, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f,
0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x74, 0x72, 0x61,
0x63, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x61, 0x65, 0x67, 0x65, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e,
0x74, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x74,
0x72, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x5f, 0x7a, 0x69, 0x70, 0x6b, 0x69, 0x6e, 0x5f, 0x65, 0x6e,
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x67, 0x72, 0x70, 0x63, 0x5f,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x67, 0x72, 0x70, 0x63,
0x5f, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x67, 0x72,
0x70, 0x63, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
0x74, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x72, 0x6f, 0x62, 0x69, 0x6e,
0x42, 0x22, 0x0a, 0x20, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x5f, 0x75, 0x72, 0x6c, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f,
0x6b, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65,
0x42, 0x27, 0x0a, 0x25, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f,
0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x42, 0x25, 0x0a, 0x23, 0x5f, 0x64, 0x61,
0x74, 0x61, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
0x5f, 0x74, 0x6c, 0x73, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79,
0x42, 0x12, 0x0a, 0x10, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f,
0x6d, 0x74, 0x6c, 0x73, 0x42, 0x39, 0x0a, 0x37, 0x5f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f,
0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73,
0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42,
0x15, 0x0a, 0x13, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x65, 0x72, 0x74, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x5f, 0x63, 0x61, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74,
0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x65, 0x72, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x42,
0x16, 0x0a, 0x14, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62,
0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f,
0x63, 0x65, 0x72, 0x74, 0x5f, 0x65, 0x61, 0x62, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x6b, 0x65, 0x79,
0x42, 0x17, 0x0a, 0x15, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x6d, 0x75,
0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x70, 0x6c, 0x65, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x61, 0x75,
0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x61,
0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f,
0x63, 0x61, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x78, 0x66, 0x66, 0x5f,
0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x78, 0x66, 0x66, 0x5f, 0x6e,
0x75, 0x6d, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x70, 0x73, 0x42,
0x1e, 0x0a, 0x1c, 0x5f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f,
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x42,
0x1b, 0x0a, 0x19, 0x5f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f,
0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x42, 0x16, 0x0a, 0x14,
0x5f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x42, 0x23, 0x0a, 0x21, 0x5f, 0x65, 0x6e, 0x76, 0x6f, 0x79, 0x5f, 0x62,
0x69, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x65, 0x6e,
0x76, 0x6f, 0x79, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
0x66, 0x72, 0x65, 0x65, 0x62, 0x69, 0x6e, 0x64, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x6f, 0x64,
0x65, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x61, 0x75, 0x64, 0x69,
0x74, 0x5f, 0x6b, 0x65, 0x79, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72,
0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, 0x65, 0x63, 0x6f,
0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x19, 0x0a, 0x17, 0x5f,
0x64, 0x61, 0x72, 0x6b, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79,
0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x61, 0x72, 0x6b, 0x6d,
0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f,
0x6c, 0x6f, 0x72, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x6f, 0x67, 0x6f, 0x5f, 0x75, 0x72, 0x6c,
0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c,
0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61,
0x70, 0x68, 0x22, 0xb0, 0x01, 0x0a, 0x16, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x4d, 0x74, 0x6c, 0x73, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x13, 0x0a,
0x02, 0x63, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x63, 0x61, 0x88,
0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x63, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48,
0x01, 0x52, 0x03, 0x63, 0x72, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x4b, 0x0a, 0x0b, 0x65, 0x6e, 0x66,
0x6f, 0x72, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24,
0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x4d, 0x74, 0x6c, 0x73, 0x45, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x4d, 0x6f, 0x64, 0x65, 0x48, 0x02, 0x52, 0x0b, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x63, 0x61, 0x42, 0x06, 0x0a,
0x04, 0x5f, 0x63, 0x72, 0x6c, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2a, 0x63, 0x0a, 0x13, 0x4d, 0x74, 0x6c, 0x73, 0x45, 0x6e, 0x66,
0x6f, 0x72, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07,
0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x4f, 0x4c,
0x49, 0x43, 0x59, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f,
0x57, 0x49, 0x54, 0x48, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x5f, 0x44, 0x45, 0x4e,
0x59, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x43, 0x4f,
0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75,
0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67,
0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
@ -2565,67 +2693,71 @@ func file_config_proto_rawDescGZIP() []byte {
return file_config_proto_rawDescData
}
var file_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_config_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
var file_config_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_config_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
var file_config_proto_goTypes = []interface{}{
(Route_AuthorizationHeaderMode)(0), // 0: pomerium.config.Route.AuthorizationHeaderMode
(*Config)(nil), // 1: pomerium.config.Config
(*RouteRewriteHeader)(nil), // 2: pomerium.config.RouteRewriteHeader
(*RouteRedirect)(nil), // 3: pomerium.config.RouteRedirect
(*Route)(nil), // 4: pomerium.config.Route
(*Policy)(nil), // 5: pomerium.config.Policy
(*Settings)(nil), // 6: pomerium.config.Settings
nil, // 7: pomerium.config.Route.AllowedIdpClaimsEntry
nil, // 8: pomerium.config.Route.SetRequestHeadersEntry
nil, // 9: pomerium.config.Route.SetResponseHeadersEntry
nil, // 10: pomerium.config.Policy.AllowedIdpClaimsEntry
(*Settings_Certificate)(nil), // 11: pomerium.config.Settings.Certificate
(*Settings_StringList)(nil), // 12: pomerium.config.Settings.StringList
nil, // 13: pomerium.config.Settings.RequestParamsEntry
nil, // 14: pomerium.config.Settings.SetResponseHeadersEntry
nil, // 15: pomerium.config.Settings.JwtClaimsHeadersEntry
(*durationpb.Duration)(nil), // 16: google.protobuf.Duration
(*v3.Cluster)(nil), // 17: envoy.config.cluster.v3.Cluster
(v31.HttpConnectionManager_CodecType)(0), // 18: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.CodecType
(*crypt.PublicKeyEncryptionKey)(nil), // 19: pomerium.crypt.PublicKeyEncryptionKey
(*structpb.ListValue)(nil), // 20: google.protobuf.ListValue
(MtlsEnforcementMode)(0), // 0: pomerium.config.MtlsEnforcementMode
(Route_AuthorizationHeaderMode)(0), // 1: pomerium.config.Route.AuthorizationHeaderMode
(*Config)(nil), // 2: pomerium.config.Config
(*RouteRewriteHeader)(nil), // 3: pomerium.config.RouteRewriteHeader
(*RouteRedirect)(nil), // 4: pomerium.config.RouteRedirect
(*Route)(nil), // 5: pomerium.config.Route
(*Policy)(nil), // 6: pomerium.config.Policy
(*Settings)(nil), // 7: pomerium.config.Settings
(*DownstreamMtlsSettings)(nil), // 8: pomerium.config.DownstreamMtlsSettings
nil, // 9: pomerium.config.Route.AllowedIdpClaimsEntry
nil, // 10: pomerium.config.Route.SetRequestHeadersEntry
nil, // 11: pomerium.config.Route.SetResponseHeadersEntry
nil, // 12: pomerium.config.Policy.AllowedIdpClaimsEntry
(*Settings_Certificate)(nil), // 13: pomerium.config.Settings.Certificate
(*Settings_StringList)(nil), // 14: pomerium.config.Settings.StringList
nil, // 15: pomerium.config.Settings.RequestParamsEntry
nil, // 16: pomerium.config.Settings.SetResponseHeadersEntry
nil, // 17: pomerium.config.Settings.JwtClaimsHeadersEntry
(*durationpb.Duration)(nil), // 18: google.protobuf.Duration
(*v3.Cluster)(nil), // 19: envoy.config.cluster.v3.Cluster
(v31.HttpConnectionManager_CodecType)(0), // 20: envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.CodecType
(*crypt.PublicKeyEncryptionKey)(nil), // 21: pomerium.crypt.PublicKeyEncryptionKey
(*structpb.ListValue)(nil), // 22: google.protobuf.ListValue
}
var file_config_proto_depIdxs = []int32{
4, // 0: pomerium.config.Config.routes:type_name -> pomerium.config.Route
6, // 1: pomerium.config.Config.settings:type_name -> pomerium.config.Settings
3, // 2: pomerium.config.Route.redirect:type_name -> pomerium.config.RouteRedirect
7, // 3: pomerium.config.Route.allowed_idp_claims:type_name -> pomerium.config.Route.AllowedIdpClaimsEntry
16, // 4: pomerium.config.Route.timeout:type_name -> google.protobuf.Duration
16, // 5: pomerium.config.Route.idle_timeout:type_name -> google.protobuf.Duration
8, // 6: pomerium.config.Route.set_request_headers:type_name -> pomerium.config.Route.SetRequestHeadersEntry
9, // 7: pomerium.config.Route.set_response_headers:type_name -> pomerium.config.Route.SetResponseHeadersEntry
2, // 8: pomerium.config.Route.rewrite_response_headers:type_name -> pomerium.config.RouteRewriteHeader
0, // 9: pomerium.config.Route.set_authorization_header:type_name -> pomerium.config.Route.AuthorizationHeaderMode
17, // 10: pomerium.config.Route.envoy_opts:type_name -> envoy.config.cluster.v3.Cluster
5, // 11: pomerium.config.Route.policies:type_name -> pomerium.config.Policy
10, // 12: pomerium.config.Policy.allowed_idp_claims:type_name -> pomerium.config.Policy.AllowedIdpClaimsEntry
12, // 13: pomerium.config.Settings.access_log_fields:type_name -> pomerium.config.Settings.StringList
12, // 14: pomerium.config.Settings.authorize_log_fields:type_name -> pomerium.config.Settings.StringList
11, // 15: pomerium.config.Settings.certificates:type_name -> pomerium.config.Settings.Certificate
16, // 16: pomerium.config.Settings.timeout_read:type_name -> google.protobuf.Duration
16, // 17: pomerium.config.Settings.timeout_write:type_name -> google.protobuf.Duration
16, // 18: pomerium.config.Settings.timeout_idle:type_name -> google.protobuf.Duration
16, // 19: pomerium.config.Settings.cookie_expire:type_name -> google.protobuf.Duration
13, // 20: pomerium.config.Settings.request_params:type_name -> pomerium.config.Settings.RequestParamsEntry
14, // 21: pomerium.config.Settings.set_response_headers:type_name -> pomerium.config.Settings.SetResponseHeadersEntry
15, // 22: pomerium.config.Settings.jwt_claims_headers:type_name -> pomerium.config.Settings.JwtClaimsHeadersEntry
16, // 23: pomerium.config.Settings.default_upstream_timeout:type_name -> google.protobuf.Duration
11, // 24: pomerium.config.Settings.metrics_certificate:type_name -> pomerium.config.Settings.Certificate
16, // 25: pomerium.config.Settings.grpc_client_timeout:type_name -> google.protobuf.Duration
18, // 26: pomerium.config.Settings.codec_type:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.CodecType
19, // 27: pomerium.config.Settings.audit_key:type_name -> pomerium.crypt.PublicKeyEncryptionKey
20, // 28: pomerium.config.Route.AllowedIdpClaimsEntry.value:type_name -> google.protobuf.ListValue
20, // 29: pomerium.config.Policy.AllowedIdpClaimsEntry.value:type_name -> google.protobuf.ListValue
30, // [30:30] is the sub-list for method output_type
30, // [30:30] is the sub-list for method input_type
30, // [30:30] is the sub-list for extension type_name
30, // [30:30] is the sub-list for extension extendee
0, // [0:30] is the sub-list for field type_name
5, // 0: pomerium.config.Config.routes:type_name -> pomerium.config.Route
7, // 1: pomerium.config.Config.settings:type_name -> pomerium.config.Settings
4, // 2: pomerium.config.Route.redirect:type_name -> pomerium.config.RouteRedirect
9, // 3: pomerium.config.Route.allowed_idp_claims:type_name -> pomerium.config.Route.AllowedIdpClaimsEntry
18, // 4: pomerium.config.Route.timeout:type_name -> google.protobuf.Duration
18, // 5: pomerium.config.Route.idle_timeout:type_name -> google.protobuf.Duration
10, // 6: pomerium.config.Route.set_request_headers:type_name -> pomerium.config.Route.SetRequestHeadersEntry
11, // 7: pomerium.config.Route.set_response_headers:type_name -> pomerium.config.Route.SetResponseHeadersEntry
3, // 8: pomerium.config.Route.rewrite_response_headers:type_name -> pomerium.config.RouteRewriteHeader
1, // 9: pomerium.config.Route.set_authorization_header:type_name -> pomerium.config.Route.AuthorizationHeaderMode
19, // 10: pomerium.config.Route.envoy_opts:type_name -> envoy.config.cluster.v3.Cluster
6, // 11: pomerium.config.Route.policies:type_name -> pomerium.config.Policy
12, // 12: pomerium.config.Policy.allowed_idp_claims:type_name -> pomerium.config.Policy.AllowedIdpClaimsEntry
14, // 13: pomerium.config.Settings.access_log_fields:type_name -> pomerium.config.Settings.StringList
14, // 14: pomerium.config.Settings.authorize_log_fields:type_name -> pomerium.config.Settings.StringList
13, // 15: pomerium.config.Settings.certificates:type_name -> pomerium.config.Settings.Certificate
18, // 16: pomerium.config.Settings.timeout_read:type_name -> google.protobuf.Duration
18, // 17: pomerium.config.Settings.timeout_write:type_name -> google.protobuf.Duration
18, // 18: pomerium.config.Settings.timeout_idle:type_name -> google.protobuf.Duration
18, // 19: pomerium.config.Settings.cookie_expire:type_name -> google.protobuf.Duration
15, // 20: pomerium.config.Settings.request_params:type_name -> pomerium.config.Settings.RequestParamsEntry
16, // 21: pomerium.config.Settings.set_response_headers:type_name -> pomerium.config.Settings.SetResponseHeadersEntry
17, // 22: pomerium.config.Settings.jwt_claims_headers:type_name -> pomerium.config.Settings.JwtClaimsHeadersEntry
18, // 23: pomerium.config.Settings.default_upstream_timeout:type_name -> google.protobuf.Duration
13, // 24: pomerium.config.Settings.metrics_certificate:type_name -> pomerium.config.Settings.Certificate
18, // 25: pomerium.config.Settings.grpc_client_timeout:type_name -> google.protobuf.Duration
8, // 26: pomerium.config.Settings.downstream_mtls:type_name -> pomerium.config.DownstreamMtlsSettings
20, // 27: pomerium.config.Settings.codec_type:type_name -> envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.CodecType
21, // 28: pomerium.config.Settings.audit_key:type_name -> pomerium.crypt.PublicKeyEncryptionKey
0, // 29: pomerium.config.DownstreamMtlsSettings.enforcement:type_name -> pomerium.config.MtlsEnforcementMode
22, // 30: pomerium.config.Route.AllowedIdpClaimsEntry.value:type_name -> google.protobuf.ListValue
22, // 31: pomerium.config.Policy.AllowedIdpClaimsEntry.value:type_name -> google.protobuf.ListValue
32, // [32:32] is the sub-list for method output_type
32, // [32:32] is the sub-list for method input_type
32, // [32:32] is the sub-list for extension type_name
32, // [32:32] is the sub-list for extension extendee
0, // [0:32] is the sub-list for field type_name
}
func init() { file_config_proto_init() }
@ -2706,8 +2838,8 @@ func file_config_proto_init() {
return nil
}
}
file_config_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Settings_Certificate); i {
file_config_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DownstreamMtlsSettings); i {
case 0:
return &v.state
case 1:
@ -2719,6 +2851,18 @@ func file_config_proto_init() {
}
}
file_config_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Settings_Certificate); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_config_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Settings_StringList); i {
case 0:
return &v.state
@ -2737,13 +2881,14 @@ func file_config_proto_init() {
file_config_proto_msgTypes[2].OneofWrappers = []interface{}{}
file_config_proto_msgTypes[3].OneofWrappers = []interface{}{}
file_config_proto_msgTypes[5].OneofWrappers = []interface{}{}
file_config_proto_msgTypes[6].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_config_proto_rawDesc,
NumEnums: 1,
NumMessages: 15,
NumEnums: 2,
NumMessages: 16,
NumExtensions: 0,
NumServices: 0,
},

View file

@ -132,6 +132,7 @@ message Policy {
string remediation = 9;
}
// Next ID: 117.
message Settings {
message Certificate {
bytes cert_bytes = 3;
@ -207,8 +208,9 @@ message Settings {
optional string databroker_storage_type = 101;
optional string databroker_storage_connection_string = 102;
optional bool databroker_storage_tls_skip_verify = 106;
optional string client_ca = 53;
optional string client_crl = 74;
optional DownstreamMtlsSettings downstream_mtls = 116;
// optional string client_ca = 53;
// optional string client_crl = 74;
optional string google_cloud_serverless_authentication_service_account = 55;
optional bool use_proxy_protocol = 107;
optional bool autocert = 56;
@ -239,3 +241,16 @@ message Settings {
optional string favicon_url = 90;
optional string error_message_first_paragraph = 91;
}
message DownstreamMtlsSettings {
optional string ca = 1;
optional string crl = 2;
optional MtlsEnforcementMode enforcement = 3;
}
enum MtlsEnforcementMode {
UNKNOWN = 0;
POLICY = 1;
POLICY_WITH_DEFAULT_DENY = 2;
REJECT_CONNECTION = 3;
}

View file

@ -0,0 +1,164 @@
package criteria
import (
"encoding/base64"
"errors"
"fmt"
"regexp"
"strings"
"github.com/open-policy-agent/opa/ast"
"github.com/pomerium/pomerium/pkg/policy/generator"
"github.com/pomerium/pomerium/pkg/policy/parser"
)
var clientCertificateBaseBody = ast.MustParseBody(`
cert := crypto.x509.parse_certificates(trim_space(input.http.client_certificate.leaf))[0]
fingerprint := crypto.sha256(base64.decode(cert.Raw))
spki_hash := base64.encode(hex.decode(
crypto.sha256(base64.decode(cert.RawSubjectPublicKeyInfo))))
`)
type clientCertificateCriterion struct {
g *Generator
}
func (clientCertificateCriterion) DataType() generator.CriterionDataType {
return CriterionDataTypeCertificateMatcher
}
func (clientCertificateCriterion) Name() string {
return "client_certificate"
}
func (c clientCertificateCriterion) GenerateRule(
_ string, data parser.Value,
) (*ast.Rule, []*ast.Rule, error) {
body := append(ast.Body(nil), clientCertificateBaseBody...)
obj, ok := data.(parser.Object)
if !ok {
return nil, nil, fmt.Errorf("expected object for certificate matcher, got: %T", data)
}
for k, v := range obj {
var err error
switch k {
case "fingerprint":
err = addCertFingerprintCondition(&body, v)
case "spki_hash":
err = addCertSPKIHashCondition(&body, v)
default:
err = fmt.Errorf("unsupported certificate matcher condition: %s", k)
}
if err != nil {
return nil, nil, err
}
}
rule := NewCriterionRule(c.g, c.Name(),
ReasonClientCertificateOK, ReasonClientCertificateUnauthorized,
body)
return rule, nil, nil
}
func addCertFingerprintCondition(body *ast.Body, data parser.Value) error {
var pa parser.Array
switch v := data.(type) {
case parser.Array:
pa = v
case parser.String:
pa = parser.Array{data}
default:
return errors.New("certificate fingerprint condition expects a string or array of strings")
}
ra := ast.NewArray()
for _, v := range pa {
f, err := canonicalCertFingerprint(v)
if err != nil {
return err
}
ra = ra.Append(ast.NewTerm(f))
}
*body = append(*body,
ast.Assign.Expr(ast.VarTerm("allowed_fingerprints"), ast.NewTerm(ra)),
ast.Equal.Expr(ast.VarTerm("fingerprint"), ast.VarTerm("allowed_fingerprints[_]")))
return nil
}
// The long certificate fingerprint format is 32 uppercase hex-encoded bytes
// separated by colons.
var longCertFingerprintRE = regexp.MustCompile("^[0-9A-F]{2}(:[0-9A-F]{2}){31}$")
// The short certificate fingerprint format is 32 lowercase hex-encoded bytes.
var shortCertFingerprintRE = regexp.MustCompile("^[0-9a-f]{64}$")
// canonicalCertFingeprint converts a single fingerprint value into the format
// that our Rego logic generates.
func canonicalCertFingerprint(data parser.Value) (ast.Value, error) {
s, ok := data.(parser.String)
if !ok {
return nil, fmt.Errorf("certificate fingerprint must be a string (was %v)", data)
}
f := string(s)
if f == "" {
return nil, errors.New("certificate fingerprint must not be empty")
} else if shortCertFingerprintRE.MatchString(f) {
return ast.String(f), nil
} else if longCertFingerprintRE.MatchString(f) {
f = strings.ToLower(strings.ReplaceAll(f, ":", ""))
return ast.String(f), nil
}
return nil, fmt.Errorf("unsupported certificate fingerprint format (%s)", f)
}
func addCertSPKIHashCondition(body *ast.Body, data parser.Value) error {
var pa parser.Array
switch v := data.(type) {
case parser.Array:
pa = v
case parser.String:
pa = parser.Array{data}
default:
return errors.New("certificate SPKI hash condition expects a string or array of strings")
}
ra := ast.NewArray()
for _, v := range pa {
s, ok := v.(parser.String)
if !ok {
return fmt.Errorf("certificate SPKI hash must be a string (was %v)", v)
}
h := string(s)
if h == "" {
return errors.New("certificate SPKI hash must not be empty")
} else if b, err := base64.StdEncoding.DecodeString(h); err != nil || len(b) != 32 {
return fmt.Errorf("certificate SPKI hash must be a base64-encoded SHA-256 hash "+
"(was %s)", h)
}
ra = ra.Append(ast.NewTerm(ast.String(h)))
}
*body = append(*body,
ast.Assign.Expr(ast.VarTerm("allowed_spki_hashes"), ast.NewTerm(ra)),
ast.Equal.Expr(ast.VarTerm("spki_hash"), ast.VarTerm("allowed_spki_hashes[_]")))
return nil
}
// ClientCertificate returns a Criterion on a client certificate.
func ClientCertificate(generator *Generator) Criterion {
return clientCertificateCriterion{g: generator}
}
func init() {
Register(ClientCertificate)
}

View file

@ -0,0 +1,203 @@
package criteria
import (
"strings"
"testing"
"github.com/open-policy-agent/opa/ast"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/pomerium/pomerium/pkg/policy/parser"
)
const testCert = `
-----BEGIN CERTIFICATE-----
MIIBYTCCAQigAwIBAgICEAEwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl
ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwNzMxMTUzMzE5WjAeMRww
GgYDVQQDExN0cnVzdGVkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEfAYP3ZwiKJgk9zXpR/CMHYlAxjweJaMJihIS2FTA5gb0xBcTEe5AGpNF
CHWPk4YCB25VeHg9GmY9Q1+qDD1hdqM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw
HwYDVR0jBBgwFoAUXep6D8FTP6+5ZdR/HjP3pYfmxkwwCgYIKoZIzj0EAwIDRwAw
RAIgProROtxpvKS/qjrjonSvacnhdU0JwoXj2DgYvF/qjrUCIAXlHkdEzyXmTLuu
/YxuOibV35vlaIzj21GRj4pYmVR1
-----END CERTIFICATE-----`
func TestClientCertificate(t *testing.T) {
t.Parallel()
cases := []struct {
label string
policy string
cert string
expected A
}{
{"no certificate",
`allow:
or:
- client_certificate:
fingerprint: 17859273e8a980631d367b2d5a6a6635412b0f22835f69e47b3f65624546a704`,
"",
A{false, A{ReasonClientCertificateUnauthorized}, M{}},
},
{"no fingerprint match",
`allow:
or:
- client_certificate:
fingerprint: df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a`,
testCert,
A{false, A{ReasonClientCertificateUnauthorized}, M{}},
},
{"fingerprint match",
`allow:
or:
- client_certificate:
fingerprint: 17859273e8a980631d367b2d5a6a6635412b0f22835f69e47b3f65624546a704`,
testCert,
A{true, A{ReasonClientCertificateOK}, M{}},
},
{"fingerprint list match",
`allow:
or:
- client_certificate:
fingerprint:
- 17859273e8a980631d367b2d5a6a6635412b0f22835f69e47b3f65624546a704
- df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a`,
testCert,
A{true, A{ReasonClientCertificateOK}, M{}},
},
{"spki hash match",
`allow:
or:
- client_certificate:
spki_hash: FsDbM0rUYIiL3V339eIKqiz6HPSB+Pz2WeAWhqlqh8U=`,
testCert,
A{true, A{ReasonClientCertificateOK}, M{}},
},
{"spki hash list match",
`allow:
or:
- client_certificate:
spki_hash:
- FsDbM0rUYIiL3V339eIKqiz6HPSB+Pz2WeAWhqlqh8U=
- NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A=`,
testCert,
A{true, A{ReasonClientCertificateOK}, M{}},
},
}
for i := range cases {
c := cases[i]
t.Run(c.label, func(t *testing.T) {
t.Parallel()
input := Input{
HTTP: InputHTTP{
ClientCertificate: ClientCertificateInfo{
Leaf: c.cert,
},
},
}
res, err := evaluate(t, c.policy, nil, input)
require.NoError(t, err)
assert.Equal(t, c.expected, res["allow"])
})
}
}
func TestCanonicalCertFingerprint(t *testing.T) {
t.Parallel()
cases := []struct {
label string
input string
output string
err string
}{
{"object",
`{}`, "", "certificate fingerprint must be a string (was {})",
},
{"empty",
`""`, "", "certificate fingerprint must not be empty",
},
{"SHA-1 fingerprint",
`"B1:E6:A2:DC:DD:6B:87:A4:9B:C5:7C:3B:7C:7F:1C:74:9A:DB:88:36"`,
"", "unsupported certificate fingerprint format (B1:E6:A2:DC:DD:6B:87:A4:9B:C5:7C:3B:7C:7F:1C:74:9A:DB:88:36)",
},
{"uppercase short",
`"DF6FF72FE9116521268F6F2DD4966F51DF479883FE7037B39F75916AC3049D1A"`,
"", "unsupported certificate fingerprint format (DF6FF72FE9116521268F6F2DD4966F51DF479883FE7037B39F75916AC3049D1A)",
},
{"valid short",
`"df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a"`,
"df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a", "",
},
{"lowercase long",
`"df:6f:f7:2f:e9:11:65:21:26:8f:6f:2d:d4:96:6f:51:df:47:98:83:fe:70:37:b3:9f:75:91:6a:c3:04:9d:1a"`,
"", "unsupported certificate fingerprint format (df:6f:f7:2f:e9:11:65:21:26:8f:6f:2d:d4:96:6f:51:df:47:98:83:fe:70:37:b3:9f:75:91:6a:c3:04:9d:1a)",
},
{"valid long",
`"DF:6F:F7:2F:E9:11:65:21:26:8F:6F:2D:D4:96:6F:51:DF:47:98:83:FE:70:37:B3:9F:75:91:6A:C3:04:9D:1A"`,
"df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a", "",
},
}
for i := range cases {
c := cases[i]
t.Run(c.label, func(t *testing.T) {
t.Parallel()
value, err := parser.ParseValue(strings.NewReader(c.input))
require.NoError(t, err)
f, err := canonicalCertFingerprint(value)
if c.err == "" {
require.NoError(t, err)
assert.Equal(t, ast.String(c.output), f)
} else {
assert.Equal(t, c.err, err.Error())
}
})
}
}
func TestSPKIHashFormatErrors(t *testing.T) {
t.Parallel()
cases := []struct {
label string
input string
err string
}{
{"object",
`{}`, "certificate SPKI hash condition expects a string or array of strings",
},
{"not base64",
`"not%valid%base64%data"`, "certificate SPKI hash must be a base64-encoded SHA-256 hash (was not%valid%base64%data)",
},
{"SHA-1 hash",
`"VYby3BAoHawLLtsyckwo5Q=="`, "certificate SPKI hash must be a base64-encoded SHA-256 hash (was VYby3BAoHawLLtsyckwo5Q==)",
},
{"valid",
`"FsDbM0rUYIiL3V339eIKqiz6HPSB+Pz2WeAWhqlqh8U="`, "",
},
}
for i := range cases {
c := cases[i]
t.Run(c.label, func(t *testing.T) {
t.Parallel()
value, err := parser.ParseValue(strings.NewReader(c.input))
require.NoError(t, err)
var body ast.Body
err = addCertSPKIHashCondition(&body, value)
if c.err == "" {
assert.NoError(t, err)
} else {
assert.Equal(t, c.err, err.Error())
}
})
}
}

View file

@ -45,6 +45,9 @@ func Register(criterionConstructor CriterionConstructor) {
}
const (
// CriterionDataTypeCertificateMatcher indicates the expected data type is
// a certificate matcher.
CriterionDataTypeCertificateMatcher CriterionDataType = "certificate_matcher"
// CriterionDataTypeStringListMatcher indicates the expected data type is a string list matcher.
CriterionDataTypeStringListMatcher CriterionDataType = "string_list_matcher"
// CriterionDataTypeStringMatcher indicates the expected data type is a string matcher.

View file

@ -43,7 +43,8 @@ type (
ID string `json:"id"`
}
ClientCertificateInfo struct {
Presented bool `json:"presented"`
Presented bool `json:"presented"`
Leaf string `json:"leaf"`
}
)

View file

@ -7,32 +7,34 @@ type Reason string
// Well-known reasons.
const (
ReasonAccept = "accept"
ReasonClaimOK = "claim-ok"
ReasonClaimUnauthorized = "claim-unauthorized"
ReasonClientCertificateRequired = "client-certificate-required"
ReasonCORSRequest = "cors-request"
ReasonDeviceOK = "device-ok"
ReasonDeviceUnauthenticated = "device-unauthenticated"
ReasonDeviceUnauthorized = "device-unauthorized"
ReasonDomainOK = "domain-ok"
ReasonDomainUnauthorized = "domain-unauthorized"
ReasonEmailOK = "email-ok"
ReasonEmailUnauthorized = "email-unauthorized"
ReasonHTTPMethodOK = "http-method-ok"
ReasonHTTPMethodUnauthorized = "http-method-unauthorized"
ReasonHTTPPathOK = "http-path-ok"
ReasonHTTPPathUnauthorized = "http-path-unauthorized"
ReasonInvalidClientCertificate = "invalid-client-certificate"
ReasonNonCORSRequest = "non-cors-request"
ReasonNonPomeriumRoute = "non-pomerium-route"
ReasonPomeriumRoute = "pomerium-route"
ReasonReject = "reject"
ReasonRouteNotFound = "route-not-found"
ReasonUserOK = "user-ok"
ReasonUserUnauthenticated = "user-unauthenticated" // user needs to log in
ReasonUserUnauthorized = "user-unauthorized" // user does not have access
ReasonValidClientCertificate = "valid-client-certificate"
ReasonAccept = "accept"
ReasonClaimOK = "claim-ok"
ReasonClaimUnauthorized = "claim-unauthorized"
ReasonClientCertificateOK = "client-certificate-ok"
ReasonClientCertificateUnauthorized = "client-certificate-unauthorized"
ReasonClientCertificateRequired = "client-certificate-required"
ReasonCORSRequest = "cors-request"
ReasonDeviceOK = "device-ok"
ReasonDeviceUnauthenticated = "device-unauthenticated"
ReasonDeviceUnauthorized = "device-unauthorized"
ReasonDomainOK = "domain-ok"
ReasonDomainUnauthorized = "domain-unauthorized"
ReasonEmailOK = "email-ok"
ReasonEmailUnauthorized = "email-unauthorized"
ReasonHTTPMethodOK = "http-method-ok"
ReasonHTTPMethodUnauthorized = "http-method-unauthorized"
ReasonHTTPPathOK = "http-path-ok"
ReasonHTTPPathUnauthorized = "http-path-unauthorized"
ReasonInvalidClientCertificate = "invalid-client-certificate"
ReasonNonCORSRequest = "non-cors-request"
ReasonNonPomeriumRoute = "non-pomerium-route"
ReasonPomeriumRoute = "pomerium-route"
ReasonReject = "reject"
ReasonRouteNotFound = "route-not-found"
ReasonUserOK = "user-ok"
ReasonUserUnauthenticated = "user-unauthenticated" // user needs to log in
ReasonUserUnauthorized = "user-unauthorized" // user does not have access
ReasonValidClientCertificate = "valid-client-certificate"
)
// Reasons is a collection of reasons.