feat(iam): add TLS configuration support for OIDC provider (#7929)
* feat(iam): add TLS configuration support for OIDC provider Adds tlsCaCert and tlsInsecureSkipVerify options to OIDC provider configuration to allow using custom CA certificates and skipping verification in development environments. * fix: use SystemCertPool for custom CA and add security warning - Use x509.SystemCertPool() to preserve trust in public CAs - Add warning log when TLSInsecureSkipVerify is enabled - Addresses code review feedback from gemini-code-assist * docs: enhance TLS configuration field documentation - Add explicit warning about TLSInsecureSkipVerify production usage - Clarify TLSCACert is for custom/self-signed certificates * security: enforce TLS 1.2 minimum version - Set MinVersion to TLS 1.2 to prevent downgrade attacks - Ensures secure communication with OIDC providers * security: validate CA cert path is absolute - Add filepath.IsAbs check before reading CA certificate - Prevents reading unintended files from relative paths - Fail fast on misconfigured paths
This commit is contained in:
@@ -5,12 +5,16 @@ import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -58,6 +62,13 @@ type OIDCConfig struct {
|
||||
|
||||
// JWKSCacheTTLSeconds sets how long to cache JWKS before refresh (default 3600 seconds)
|
||||
JWKSCacheTTLSeconds int `json:"jwksCacheTTLSeconds,omitempty"`
|
||||
|
||||
// TLSCACert is the path to the CA certificate file for custom/self-signed certificates
|
||||
TLSCACert string `json:"tlsCaCert,omitempty"`
|
||||
|
||||
// TLSInsecureSkipVerify controls whether to skip TLS verification.
|
||||
// WARNING: Should only be used in development/testing environments. Never use in production.
|
||||
TLSInsecureSkipVerify bool `json:"tlsInsecureSkipVerify,omitempty"`
|
||||
}
|
||||
|
||||
// JWKS represents JSON Web Key Set
|
||||
@@ -124,6 +135,45 @@ func (p *OIDCProvider) Initialize(config interface{}) error {
|
||||
p.jwksTTL = time.Hour
|
||||
}
|
||||
|
||||
// Configure HTTP client with TLS settings
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: oidcConfig.TLSInsecureSkipVerify,
|
||||
MinVersion: tls.VersionTLS12, // Prevent TLS downgrade attacks
|
||||
}
|
||||
|
||||
if oidcConfig.TLSInsecureSkipVerify {
|
||||
glog.Warningf("OIDC provider %q is configured to skip TLS verification. This is insecure and should not be used in production.", p.name)
|
||||
}
|
||||
|
||||
if oidcConfig.TLSCACert != "" {
|
||||
// Validate that the CA cert path is absolute to prevent reading unintended files
|
||||
if !filepath.IsAbs(oidcConfig.TLSCACert) {
|
||||
return fmt.Errorf("TLSCACert must be an absolute path, got: %s", oidcConfig.TLSCACert)
|
||||
}
|
||||
|
||||
caCert, err := os.ReadFile(oidcConfig.TLSCACert)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read CA cert file: %w", err)
|
||||
}
|
||||
// Start with the system cert pool to trust public CAs, then add the custom one.
|
||||
rootCAs, _ := x509.SystemCertPool()
|
||||
if rootCAs == nil {
|
||||
rootCAs = x509.NewCertPool()
|
||||
}
|
||||
if !rootCAs.AppendCertsFromPEM(caCert) {
|
||||
return fmt.Errorf("failed to append CA cert from file: %s", oidcConfig.TLSCACert)
|
||||
}
|
||||
tlsConfig.RootCAs = rootCAs
|
||||
}
|
||||
|
||||
transport := &http.Transport{
|
||||
TLSClientConfig: tlsConfig,
|
||||
}
|
||||
p.httpClient = &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
// For testing, we'll skip the actual OIDC client initialization
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -49,8 +49,10 @@ const (
|
||||
ConfigFieldClientSecret = "clientSecret"
|
||||
ConfigFieldJWKSUri = "jwksUri"
|
||||
ConfigFieldScopes = "scopes"
|
||||
ConfigFieldUserInfoUri = "userInfoUri"
|
||||
ConfigFieldRedirectUri = "redirectUri"
|
||||
ConfigFieldUserInfoUri = "userInfoUri"
|
||||
ConfigFieldRedirectUri = "redirectUri"
|
||||
ConfigFieldTLSCACert = "tlsCaCert"
|
||||
ConfigFieldTLSInsecureSkipVerify = "tlsInsecureSkipVerify"
|
||||
)
|
||||
|
||||
// Error Messages
|
||||
|
||||
@@ -115,6 +115,14 @@ func (f *ProviderFactory) convertToOIDCConfig(configMap map[string]interface{})
|
||||
config.Scopes = scopes
|
||||
}
|
||||
|
||||
if tlsCaCert, ok := configMap[ConfigFieldTLSCACert].(string); ok {
|
||||
config.TLSCACert = tlsCaCert
|
||||
}
|
||||
|
||||
if tlsInsecureSkipVerify, ok := configMap[ConfigFieldTLSInsecureSkipVerify].(bool); ok {
|
||||
config.TLSInsecureSkipVerify = tlsInsecureSkipVerify
|
||||
}
|
||||
|
||||
// Convert claims mapping
|
||||
if claimsMapInterface, ok := configMap["claimsMapping"]; ok {
|
||||
claimsMap, err := f.convertToStringMap(claimsMapInterface)
|
||||
|
||||
Reference in New Issue
Block a user