This partially reverts commit a1388592d8.
Fetching the authenticate service HPKE public key is required only for
the stateless authentication flow. Now that Pomerium will instead use
the older (stateful) authentication flow when configured for a
self-hosted authenticate service, this logic shouldn't be needed at all.
Removing this logic should also make it easier to test against a local
instance of the hosted authenticate service.
Add an environment variable to allow forcing either the stateful or the
stateless authenticate flow.
Split the existing integration test clusters "single" and "multi" into
four new clusters: "single-stateful", "single-stateless",
"multi-stateful", and "multi-stateless", so that the integration tests
will run for both the stateful and the stateless authenticate flows.
(The "kubernetes" cluster is not currently being run, so I've left it
alone for now.)
Update the initialization logic for the authenticate, authorize, and
proxy services to automatically select between the stateful
authentication flow and the stateless authentication flow, depending on
whether Pomerium is configured to use the hosted authenticate service.
Add a unit test case to verify that the sign_out handler does not
trigger a sign in redirect.
* core/config: update file watcher source to handle base64 encoded certificates
* fix data race
* core/config: only allow files in certificates
* remove test
* re-add test
* core/config: refactor file watcher
* add comments
* updates
* only use the polling watcher
* fix test
* fix test
* try to fix test again
* remove batching
* dont rely on file modification timestamp
* remove benchmark
* try fix again
Remove the Redis databroker backend. According to
https://www.pomerium.com/docs/internals/data-storage#redis it has been
discouraged since Pomerium v0.18.
Update the config options validation to return an error if "redis" is
set as the databroker storage backend type.
* core/config: refactor change dispatcher
* update test
* close listener go routine when context is canceled
* use cancel cause
* use context
* add more time
* more time
Currently the GetSetResponseHeadersForPolicy() method may add entries to
the global SetResponseHeaders map, which can lead to one route's headers
being applied to other routes.
Instead, make a copy of the SetResponseHeaders map before adding any
route-specific response header entries.
Add additional unit tests for GetSetResponseHeaders() and
GetSetResponseHeadersForPolicy().
Remove the deprecated set_authorization_header option entirely. Add an
entry to the removedConfigFields map with a link to the relevant
Upgrading page section.
Set the Envoy option only_verify_leaf_cert_crl, to avoid a bug where
CRLs cannot be used in combination with an intermediate CA trust root.
Update the client certificate validation logic in the authorize service
to match this behavior.
Fix the logic around when to add the default invalid_client_certificate
rule: this should only be added if mTLS is enabled and the enforcement
mode is not set to "policy". Add a unit test for this logic.
If Pomerium is operating in the insecure_server mode (e.g. if there is
another reverse proxy in front of Pomerium), then the ssl() Lua method
will return nil.
Add a check for this case to the set-client-certificate-metadata.lua
script, in order to avoid an error when attempting to store the client
certificate info.
Currently Pomerium replaces dynamic set_request_headers tokens
sequentially. As a result, if a replacement value itself contained a
supported "$pomerium" token, Pomerium may treat that as another
replacement, resulting in incorrect output.
This is unlikely to be a problem given the current set of dynamic
tokens, but if we continue to add additional tokens, this will likely
become more of a concern.
To forestall any issues, let's perform all replacements in one pass,
using the os.Expand() method. This does require a slight change to the
syntax, as tokens containing a '.' will need to be wrapped in curly
braces, e.g. ${pomerium.id_token}.
A literal dollar sign can be included by using $$ in the input.
Add a new match_subject_alt_names option to the downstream_mtls settings
group. This setting can be used to further constrain the allowed client
certificates by requiring that certificates contain a Subject
Alternative Name of a particular type, matching a particular regex.
When set, populate the corresponding match_typed_subject_alt_names
setting within Envoy, and also implement a corresponding check in the
authorize service.
Move the parseCRLs() method from package 'authorize/evaluator' to
'pkg/cryptutil', replacing the existing DecodeCRL() method. This method
will parse all CRLs found in the PEM input, rather than just the first.
(This removes our usage of the deprecated method x509.ParseDERCRL.)
Update this method to return an error if there is non-PEM data found in
the input, to satisfy the existing test that raw DER-encoded CRLs are
not permitted.
Delete the CRLFromBase64() and CRLFromFile() methods, as these are no
longer used.
Add a new max_verify_depth option to the downstream_mtls settings group,
with a default value of 1 (to match the behavior of current Pomerium
releases).
Populate the corresponding setting within Envoy, and also implement a
depth check within isValidClientCertificate() in the authorize service.
Add an "enforcement" option to the new downstream mTLS configuration
settings group.
When not set, or when set to "policy_default_deny", keep the current
behavior of adding an invalid_client_certificate rule to all policies.
When the enforcement mode is set to just "policy", remove the default
invalid_client_certificate rule that would be normally added.
When the enforcement mode is set to "reject_connection", configure the
Envoy listener with the require_client_certificate setting and remove
the ACCEPT_UNTRUSTED option.
Add a corresponding field to the Settings proto.
Move downstream mTLS settings to a nested config file object, under the
key 'downstream_mtls', and add a new DownstreamMTLSSettings struct for
these settings.
Deprecate the existing ClientCA and ClientCAFile fields in the Options
struct, but continue to honor them for now (log a warning if either is
populated).
Delete the ClientCRL and ClientCRLFile fields entirely (in current
releases these cannot be set without causing an Envoy error, so this
should not be a breaking change).
Update the Settings proto to mirror this nested structure.
Update bindEnvs() to add support for binding nested fields of the
Options struct to environment variables. The variable names are formed
by joining the nested fields' mapstructure tags with underscores (after
first converting to uppercase).
This is in preparation for adding a new nested struct for downstream
mTLS settings that will look something like this:
downstream_mtls:
ca_file: /path/to/CA/cert.pem
enforcement: reject_connection
With this change, these fields would be bound to the variables
DOWNSTREAM_MTLS_CA_FILE and DOWNSTREAM_MTLS_ENFORCEMENT.
Update isValidClientCertificate() to also consult the configured
certificate revocation lists. Update existing test cases and add a new
unit test to exercise the revocation support. Restore the skipped
integration test case.
Generate new test certificates and CRLs using a new `go run`-able source
file.
Partially revert #4374: do not record the peerCertificateValidated()
result as reported by Envoy, as this does not work correctly for resumed
TLS sessions. Instead always record the certificate chain as presented
by the client. Remove the corresponding ClientCertificateInfo Validated
field, and update affected code accordingly. Skip the CRL integration
test case for now.
* config: add customization options for logging
* config: validate log fields
* proxy: add support for logging http request headers
* log subset of headers
* fix test name
* dont use log.HTTPHeaders for access logs
* canonicalize http/2 headers
Currently we always add an invalid_client_certificate deny rule to all
PPL policies. Instead, let's add this rule only when a client CA is
configured. This way, if a user is not using client certificates at all,
they won't see any reason strings related to client certificates in the
authorize logs.
Change the "valid-client-certificate-or-none-required" reason string to
just "valid-client-certificate" accordingly.
Pass the main Evaluator config to NewPolicyEvaluator so that we can
determine whether there is a client CA configured or not. Extract the
existing default deny rule to a separate method. Add unit tests
exercising the new behavior.
Configure Envoy to validate client certificates, using the union of all
relevant client CA bundles (that is, a bundle of the main client CA
setting together with all per-route client CAs). Pass the validation
status from Envoy through to the authorize service, by configuring Envoy
to use the newly-added SetClientCertificateMetadata filter, and by also
adding the relevant metadata namespace to the ExtAuthz configuration.
Remove the existing 'include_peer_certificate' setting from the ExtAuthz
configuration, as the metadata from the Lua filter will include the full
certificate chain (when it validates successfully by Envoy).
Update policy evaluation to consider the validation status from Envoy,
in addition to its own certificate chain validation. (Policy evaluation
cannot rely solely on the Envoy validation status while we still support
the per-route client CA setting.)
When building an upstream validation context for a particular URL, check
whether the hostname is an IP address. If so, configure the SAN match to
use type IP_ADDRESS rather than DNS.
Add a new Lua filter that will store client certificate info as dynamic
metadata. This will allow us to configure client certificate validation
at the Envoy listener level, and then pass the results of that
validation into our ExtAuthz service.
This also allows us to pass the entire client certificate chain (and not
just the leaf certificate, which is how the 'include_peer_certificate'
ExtAuthz setting behaves). This will allow us to add support for
intermediate CA certificates supplied by the client.
However, if a client certificate does not validate successfully by
Envoy, we will not store the certificate chain. (This should help guard
against any possibility of making policy decisions based on unvalidated
client certificate data.)
Pomerium configures a gRPC listener in Envoy, for internal communication
between the various Pomerium services. Currently this listener shares
much of the same configuration as the main HTTP listener, based on the
main Pomerium configuration options.
However, some configuration options don't make sense for the gRPC
listener. Specifically, the `codec_type` option should not be applied to
the gRPC listener, as gRPC requires HTTP/2. Also, any client certificate
settings should not apply to the gRPC listener.
Separate the gRPC listener configuration from the main HTTP listener
configuration, so we can avoid applying these configuration options.
Instead set AlpnProtocols to just "h2" (HTTP/2), and do not set any
ValidationContextType on the DownstreamTlsContext (no client certificate
validation).
Specifically, inline the call to buildTLSSocket() within the body of
buildGRPCListener(). Extract a new method envoyCertificates() from
buildDownstreamTLSContextMulti(), to avoid repeating this logic.
Fetch the HPKE public key only when configured to use the hosted
authenticate service. Determine whether we are using the hosted
authenticate service by comparing the resolved authenticate domain with
a hard-coded list of hosted authenticate domains.
Extract this list of hosted authenticate domains to the internal/urlutil
package in order to keep a single source of truth for this data.
Allow users to clear the default IdP auth code options, by explicitly
setting an empty idp_request_params map.
To do this in a YAML config file, set:
idp_request_params: {}