Add vault_sni config for container TLS hostname override
The web UI connects to the vault API via gRPC using the Docker compose service name (e.g., "metacrypt:9443"), but the vault's TLS certificate has SANs for "crypt.metacircular.net" and "localhost". The new vault_sni config field overrides the TLS ServerName so certificate verification succeeds despite the hostname mismatch. Also updates metacrypt-rift.toml with vault_sni and temporarily binds the web UI port to 0.0.0.0 for direct access until mc-proxy is deployed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,7 @@ services:
|
||||
restart: unless-stopped
|
||||
user: "0:0"
|
||||
ports:
|
||||
- "127.0.0.1:18080:8080"
|
||||
- "0.0.0.0:18080:8080" # TODO: revert to 127.0.0.1 once mc-proxy is deployed
|
||||
volumes:
|
||||
- /srv/metacrypt:/srv/metacrypt
|
||||
depends_on:
|
||||
|
||||
@@ -46,6 +46,10 @@ type WebConfig struct {
|
||||
VaultGRPC string `toml:"vault_grpc"`
|
||||
// VaultCACert is the path to the CA certificate used to verify the vault's TLS cert.
|
||||
VaultCACert string `toml:"vault_ca_cert"`
|
||||
// VaultSNI overrides the TLS server name used to verify the vault's
|
||||
// certificate. Use when the dial address (e.g., a container hostname)
|
||||
// does not match any SAN on the vault's TLS certificate.
|
||||
VaultSNI string `toml:"vault_sni"`
|
||||
// TLSCert and TLSKey are optional. If empty, the web server uses plain HTTP
|
||||
// (suitable for deployment behind a TLS-terminating reverse proxy).
|
||||
TLSCert string `toml:"tls_cert"`
|
||||
|
||||
@@ -31,10 +31,16 @@ type VaultClient struct {
|
||||
}
|
||||
|
||||
// NewVaultClient dials the vault gRPC server and returns a client.
|
||||
func NewVaultClient(addr, caCertPath string, logger *slog.Logger) (*VaultClient, error) {
|
||||
// NewVaultClient creates a gRPC client to the metacrypt vault API server.
|
||||
// If sni is non-empty, it overrides the TLS server name for certificate
|
||||
// verification (use when the dial address doesn't match a cert SAN).
|
||||
func NewVaultClient(addr, caCertPath, sni string, logger *slog.Logger) (*VaultClient, error) {
|
||||
logger.Debug("connecting to vault", "addr", addr, "ca_cert", caCertPath)
|
||||
|
||||
tlsCfg := &tls.Config{MinVersion: tls.VersionTLS13}
|
||||
tlsCfg := &tls.Config{MinVersion: tls.VersionTLS13} //nolint:gosec // TLS 1.3 minimum
|
||||
if sni != "" {
|
||||
tlsCfg.ServerName = sni
|
||||
}
|
||||
if caCertPath != "" {
|
||||
logger.Debug("loading vault CA certificate", "path", caCertPath)
|
||||
pemData, err := os.ReadFile(caCertPath) //nolint:gosec
|
||||
|
||||
@@ -143,7 +143,7 @@ func (ws *WebServer) resolveUser(id string) string {
|
||||
// New creates a new WebServer. It dials the vault gRPC endpoint.
|
||||
func New(cfg *config.Config, logger *slog.Logger) (*WebServer, error) {
|
||||
logger.Info("connecting to vault", "addr", cfg.Web.VaultGRPC, "ca_cert", cfg.Web.VaultCACert)
|
||||
vault, err := NewVaultClient(cfg.Web.VaultGRPC, cfg.Web.VaultCACert, logger)
|
||||
vault, err := NewVaultClient(cfg.Web.VaultGRPC, cfg.Web.VaultCACert, cfg.Web.VaultSNI, logger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("webserver: connect to vault: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user