feat: support mTLS-only authn/authz with AccessControl and allow combining mTLS with other auth mechanisms (#3624)

* feat: support mTLS-only authn/authz with AccessControl and allow combining mTLS with other auth mechanisms

Signed-off-by: Ivan Arkhipov <me@endevir.ru>

* refactor: improve authentication logic and TLS certificate generation

- Fix mTLS authentication to use only leaf certificate instead of iterating
  through all certificates in the chain
- Reject Authorization headers when corresponding auth method is disabled,
  regardless of mTLS status (security improvement)
- Simplify authentication switch statement ordering and logic
- Move ErrUserDataNotFound error handling into sessionAuthn method
- Refactor TLS certificate generation to use Options pattern with
  CertificateOptions struct for better extensibility
- Consolidate duplicate certificate generation code into helper functions
  (generateCertificate, parseCA, initializeTemplate, applyOptions)
- Rename certificate generation functions for clarity:
  - GenerateCertWithCN -> GenerateClientCert
  - GenerateSelfSignedCertWithCN -> GenerateClientSelfSignedCert
- Add support for SAN settings including email addresses in certificates
- Update tests to reflect new authentication behavior and certificate API

This commit improves both the security posture (rejecting disabled auth
methods) and code maintainability (consolidated certificate generation).

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>

* fix: guard against multiple Authorization headers

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>

---------

Signed-off-by: Ivan Arkhipov <me@endevir.ru>
Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
Co-authored-by: Ivan Arkhipov <me@endevir.ru>
This commit is contained in:
Andrei Aaron
2025-12-11 20:08:32 +02:00
committed by GitHub
parent e7b73b6c2d
commit 08fae9104d
11 changed files with 2066 additions and 536 deletions
+3 -6
View File
@@ -240,11 +240,6 @@ func (c *Controller) Run() error {
}
if tlsConfig.CACert != "" {
clientAuth := tls.VerifyClientCertIfGiven
if c.Config.IsMTLSAuthEnabled() {
clientAuth = tls.RequireAndVerifyClientCert
}
caCert, err := os.ReadFile(tlsConfig.CACert)
if err != nil {
c.Log.Error().Err(err).Str("caCert", tlsConfig.CACert).Msg("failed to read file")
@@ -260,7 +255,9 @@ func (c *Controller) Run() error {
return errors.ErrBadCACert
}
server.TLSConfig.ClientAuth = clientAuth
// Use VerifyClientCertIfGiven even if mTLS is enabled: clients without cert will be treated as anonymous
// You can control permissions for mTLS anonymous requests via accessControl policies
server.TLSConfig.ClientAuth = tls.VerifyClientCertIfGiven
server.TLSConfig.ClientCAs = caCertPool
}