RBAC (api/internal/authz) is live on /query and /dashboards, backed by a new enterprise/ module (session issuance, audit logging, RBAC storage, OIDC/SAML protocol wiring) that core never imports -- only calls over HTTP. Found and fixed a real cross-tenant vulnerability in dashboards (no tenant_id filtering at all) while writing the threat model doc. Two things are explicitly NOT done, documented rather than hidden: tenant isolation for log data itself (/query still shares one ClickHouse connection and Tantivy index across every tenant -- RBAC controls who can query, not what a query can see), and human SSO login (protocol wiring exists, no HTTP handler calls it yet). See docs/security/threat-model.md and docs/phase-4-runbook.md. Also adds deploy/ (Go Operator + Helm chart, validated offline only -- no cluster was reachable in this environment).
92 lines
2.8 KiB
Go
92 lines
2.8 KiB
Go
// Package config loads enterprise-auth's configuration from environment
|
|
// variables, same convention as every other Go service in this repo.
|
|
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
type Config struct {
|
|
HTTPListenAddr string
|
|
Postgres PostgresConfig
|
|
OIDC OIDCConfig
|
|
SAML SAMLConfig
|
|
SessionSigningKey []byte
|
|
}
|
|
|
|
type PostgresConfig struct {
|
|
Addr string
|
|
Database string
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
// OIDCConfig is optional -- a deployment might configure OIDC, SAML,
|
|
// both, or (during early rollout) neither yet. Load() doesn't fail if
|
|
// these are unset; internal/oidc.New is only called once IssuerURL is
|
|
// actually present.
|
|
type OIDCConfig struct {
|
|
IssuerURL string
|
|
ClientID string
|
|
ClientSecret string
|
|
RedirectURL string
|
|
}
|
|
|
|
// SAMLConfig is likewise optional. Note this only records *presence* --
|
|
// enough for /auth/features (internal/authhandler) to report
|
|
// saml_enabled -- it does not itself fetch/parse IDPMetadataURL into the
|
|
// *saml.EntityDescriptor internal/saml.New requires; that fetch (and the
|
|
// login/ACS HTTP handlers that would use it) is deferred, same as OIDC's
|
|
// login/callback handlers -- see cmd/enterprise-auth/main.go's doc
|
|
// comment.
|
|
type SAMLConfig struct {
|
|
EntityID string
|
|
ACSURL string
|
|
IDPMetadataURL string
|
|
}
|
|
|
|
func Load() (Config, error) {
|
|
cfg := Config{
|
|
HTTPListenAddr: getenv("HTTP_LISTEN_ADDR", ":8082"),
|
|
Postgres: PostgresConfig{
|
|
Addr: getenv("POSTGRES_ADDR", "localhost:5432"),
|
|
Database: getenv("POSTGRES_DATABASE", "sentry_metadata"),
|
|
Username: getenv("POSTGRES_USERNAME", "sentry"),
|
|
Password: getenv("POSTGRES_PASSWORD", ""),
|
|
},
|
|
OIDC: OIDCConfig{
|
|
IssuerURL: getenv("OIDC_ISSUER_URL", ""),
|
|
ClientID: getenv("OIDC_CLIENT_ID", ""),
|
|
ClientSecret: getenv("OIDC_CLIENT_SECRET", ""),
|
|
RedirectURL: getenv("OIDC_REDIRECT_URL", ""),
|
|
},
|
|
SAML: SAMLConfig{
|
|
EntityID: getenv("SAML_ENTITY_ID", ""),
|
|
ACSURL: getenv("SAML_ACS_URL", ""),
|
|
IDPMetadataURL: getenv("SAML_IDP_METADATA_URL", ""),
|
|
},
|
|
}
|
|
|
|
// Required, unlike OIDC/SAML above: every enterprise-auth deployment
|
|
// issues and validates session/service tokens (internal/session),
|
|
// even one that hasn't configured any IdP yet. 32 bytes matches
|
|
// internal/session.MinSigningKeyBytes -- not imported here to avoid
|
|
// a config->session dependency for one constant, but the two values
|
|
// must be kept in sync.
|
|
signingKey := getenv("ENTERPRISE_SESSION_SIGNING_KEY", "")
|
|
if len(signingKey) < 32 {
|
|
return Config{}, fmt.Errorf("ENTERPRISE_SESSION_SIGNING_KEY must be set to at least 32 bytes (got %d)", len(signingKey))
|
|
}
|
|
cfg.SessionSigningKey = []byte(signingKey)
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func getenv(key, fallback string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|