Merge pull request #146 from pgsty/fix/issue-108-console-loopback-tls

fix: keep embedded Console login working over loopback TLS (#108)
This commit is contained in:
Feng Ruohang
2026-09-07 10:53:45 +08:00
committed by GitHub
2 changed files with 83 additions and 5 deletions
+30 -5
View File
@@ -120,15 +120,40 @@ func init() {
const consolePrefix = "CONSOLE_"
// consoleMinIOServerEnv derives the CONSOLE_MINIO_SERVER value the embedded
// Console uses to reach the S3/STS API, and whether TLS verification of that
// endpoint must be skipped. With no explicit endpoint configured the Console
// reaches the API over the loopback address, whose TLS certificate is not
// expected to carry a 127.0.0.1 SAN; because Console verifies outbound TLS by
// default, the loopback origin has to be exempted or embedded login (local and
// LDAP alike) fails at the STS handshake. The exemption is endpoint-scoped in
// Console, so every other HTTPS peer stays verified. An explicitly configured
// endpoint is always reached under its own verified name and is never exempted.
func consoleMinIOServerEnv(endpoint string, isTLS bool, port string) (server string, skipVerify bool) {
if endpoint != "" {
return endpoint, false
}
return fmt.Sprintf("%s://127.0.0.1:%s", getURLScheme(isTLS), port), isTLS
}
func minioConfigToConsoleFeatures() {
os.Setenv("CONSOLE_PBKDF_SALT", globalDeploymentID())
os.Setenv("CONSOLE_PBKDF_PASSPHRASE", globalDeploymentID())
if globalMinioEndpoint != "" {
os.Setenv("CONSOLE_MINIO_SERVER", globalMinioEndpoint)
consoleServer, skipVerify := consoleMinIOServerEnv(globalMinioEndpoint, globalIsTLS, globalMinioPort)
os.Setenv("CONSOLE_MINIO_SERVER", consoleServer)
if skipVerify {
// The embedded Console reaches the loopback S3/STS endpoint above, whose
// certificate is not expected to carry a 127.0.0.1 SAN. Console verifies
// outbound TLS by default (silo-console v2.3.x), so opt into the
// endpoint-scoped compatibility switch to preserve the documented loopback
// bypass; every other HTTPS peer (IdP, Prometheus, webhooks, ...) stays
// verified. initConsoleServer unsets CONSOLE_* before calling this, so the
// switch cannot be supplied by the operator on the embedded path.
os.Setenv("CONSOLE_MINIO_SERVER_TLS_SKIP_VERIFY", "on")
} else {
// Explicitly set 127.0.0.1 so Console will automatically bypass TLS verification to the local S3 API.
// This will save users from providing a certificate with IP or FQDN SAN that points to the local host.
os.Setenv("CONSOLE_MINIO_SERVER", fmt.Sprintf("%s://127.0.0.1:%s", getURLScheme(globalIsTLS), globalMinioPort))
// An explicitly configured endpoint is reached under its own verified name;
// never let a loopback exemption apply to it.
os.Unsetenv("CONSOLE_MINIO_SERVER_TLS_SKIP_VERIFY")
}
if value := env.Get(config.EnvMinIOLogQueryURL, ""); value != "" {
os.Setenv("CONSOLE_LOG_QUERY_URL", value)
+53
View File
@@ -372,3 +372,56 @@ func TestConfigEnvFileNamedTargetDiscovery(t *testing.T) {
t.Fatalf("named target %q not discovered from %s: %v", "my-hook", key, targets)
}
}
// TestConsoleMinIOServerEnv locks in the loopback TLS exemption that keeps
// embedded Console login working (issue #108) while ensuring an explicitly
// configured endpoint is never silently exempted from TLS verification.
func TestConsoleMinIOServerEnv(t *testing.T) {
tests := []struct {
name string
endpoint string
isTLS bool
port string
wantServer string
wantSkipVerify bool
}{
{
name: "loopback TLS is exempted so embedded login works",
isTLS: true,
port: "9000",
wantServer: "https://127.0.0.1:9000",
wantSkipVerify: true,
},
{
name: "loopback plain HTTP needs no exemption",
isTLS: false,
port: "9000",
wantServer: "http://127.0.0.1:9000",
},
{
name: "explicit https endpoint stays verified",
endpoint: "https://silo.example:9000",
isTLS: true,
port: "9000",
wantServer: "https://silo.example:9000",
},
{
name: "explicit http endpoint stays verified",
endpoint: "http://silo.example:9000",
isTLS: false,
port: "9000",
wantServer: "http://silo.example:9000",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, skipVerify := consoleMinIOServerEnv(tt.endpoint, tt.isTLS, tt.port)
if server != tt.wantServer {
t.Fatalf("server = %q, want %q", server, tt.wantServer)
}
if skipVerify != tt.wantSkipVerify {
t.Fatalf("skipVerify = %v, want %v", skipVerify, tt.wantSkipVerify)
}
})
}
}