From 872d1cbcfaf4aa7123d51f086f2ab1774f42e57a Mon Sep 17 00:00:00 2001 From: "m.nabokikh" Date: Thu, 28 Jan 2021 01:25:25 +0400 Subject: [PATCH] feat: gotemplate formatting for Dex config file Signed-off-by: m.nabokikh --- cmd/dex/config.go | 44 ++++++++++++++++++++++++++++++ cmd/dex/config_test.go | 42 +++++++++++++++++++++++++++++ cmd/dex/serve.go | 16 +++-------- examples/config-tmpl.yaml | 56 +++++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 23 ++++++++++++++++ 6 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 examples/config-tmpl.yaml diff --git a/cmd/dex/config.go b/cmd/dex/config.go index 88dc98e720..4bf36baee7 100644 --- a/cmd/dex/config.go +++ b/cmd/dex/config.go @@ -1,13 +1,18 @@ package main import ( + "bytes" "encoding/base64" "encoding/json" "fmt" + "io/ioutil" "os" "strconv" "strings" + "text/template" + "github.com/Masterminds/sprig/v3" + "github.com/ghodss/yaml" "golang.org/x/crypto/bcrypt" "github.com/dexidp/dex/pkg/log" @@ -50,6 +55,45 @@ type Config struct { StaticPasswords []password `json:"staticPasswords"` } +func newConfigByPath(configFile string, options serveOptions) (*Config, error) { + configData, err := ioutil.ReadFile(configFile) + if err != nil { + return nil, fmt.Errorf("failed to read config file %s: %w", configFile, err) + } + + config, err := newConfigFromData(configData, options) + if err != nil { + return nil, fmt.Errorf("error parse config file %s: %w", configFile, err) + } + + return config, nil +} + +func newConfigFromData(configData []byte, options serveOptions) (*Config, error) { + tmpls, err := template.New("dex").Funcs(sprig.TxtFuncMap()).Parse(string(configData)) + if err != nil { + return nil, fmt.Errorf("parse template: %w", err) + } + + buff := new(bytes.Buffer) + err = tmpls.Execute(buff, nil) + if err != nil { + return nil, err + } + + var config Config + if err := yaml.Unmarshal(buff.Bytes(), &config); err != nil { + return nil, err + } + + applyConfigOverrides(options, &config) + if err := config.Validate(); err != nil { + return nil, err + } + + return &config, nil +} + // Validate the configuration func (c Config) Validate() error { // Fast checks. Perform these first for a more responsive CLI. diff --git a/cmd/dex/config_test.go b/cmd/dex/config_test.go index 8ee02d5aa2..5c81d0f89a 100644 --- a/cmd/dex/config_test.go +++ b/cmd/dex/config_test.go @@ -6,6 +6,7 @@ import ( "github.com/ghodss/yaml" "github.com/kylelemons/godebug/pretty" + "github.com/stretchr/testify/require" "github.com/dexidp/dex/connector/mock" "github.com/dexidp/dex/connector/oidc" @@ -423,3 +424,44 @@ logger: t.Errorf("got!=want: %s", diff) } } + +func TestUnmarshalConfigTemplate(t *testing.T) { + err := os.Setenv("DEX_TEST_ENV_ISSUER_BASE64", "aHR0cDovLzEyNy4wLjAuMTo1NTU2L2RleC10ZXN0Cg==") + require.NoError(t, err) + + rawConfig := []byte(` +{{ $ := fromJson "{}" }} +{{ $_ := set $ "http" "0.0.0.0:5555" }} +{{ $_ := set $ "https" "0.0.0.0:6666" }} +{{ $_ := set $ "tlsCert" "tls.crt" }} +{{ $_ := set $ "tlsKey" "tls.key" }} + +issuer: {{ env "DEX_TEST_ENV_ISSUER_BASE64" | b64dec }} +storage: + type: {{ env "NON_EXISTED_ENV" | default "sqlite3" }} + config: + file: {{ base "/etc/test.db" }} +web: {{ $ | toJson }} +`) + want := Config{ + Issuer: "http://127.0.0.1:5556/dex-test", + Storage: Storage{ + Type: "sqlite3", + Config: &sql.SQLite3{ + File: "test.db", + }, + }, + Web: Web{ + HTTP: "0.0.0.0:5555", + HTTPS: "0.0.0.0:6666", + TLSCert: "tls.crt", + TLSKey: "tls.key", + }, + } + + c, err := newConfigFromData(rawConfig, serveOptions{}) + require.NoError(t, err) + + diff := pretty.Compare(c, want) + require.Equal(t, "", diff) +} diff --git a/cmd/dex/serve.go b/cmd/dex/serve.go index 634e2606e1..cc9d7a5610 100644 --- a/cmd/dex/serve.go +++ b/cmd/dex/serve.go @@ -13,7 +13,6 @@ import ( "strings" "time" - "github.com/ghodss/yaml" grpcprometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -70,18 +69,12 @@ func commandServe() *cobra.Command { func runServe(options serveOptions) error { configFile := options.config - configData, err := ioutil.ReadFile(configFile) - if err != nil { - return fmt.Errorf("failed to read config file %s: %v", configFile, err) - } - var c Config - if err := yaml.Unmarshal(configData, &c); err != nil { - return fmt.Errorf("error parse config file %s: %v", configFile, err) + c, err := newConfigByPath(configFile, options) + if err != nil { + return err } - applyConfigOverrides(options, &c) - logger, err := newLogger(c.Logger.Level, c.Logger.Format) if err != nil { return fmt.Errorf("invalid config: %v", err) @@ -89,9 +82,6 @@ func runServe(options serveOptions) error { if c.Logger.Level != "" { logger.Infof("config using log level: %s", c.Logger.Level) } - if err := c.Validate(); err != nil { - return err - } logger.Infof("config issuer: %s", c.Issuer) diff --git a/examples/config-tmpl.yaml b/examples/config-tmpl.yaml new file mode 100644 index 0000000000..01f39fd1da --- /dev/null +++ b/examples/config-tmpl.yaml @@ -0,0 +1,56 @@ +issuer: {{ env "DEX_ISSUER" | default "http://127.0.0.1:5556/dex" }} + +storage: + type: sqlite3 + config: + file: {{ env "DEX_STORAGE_SQLITE3_CONFIG_FILE" | default "/etc/dex/dex.db" }} + +web: +{{- if env "DEX_WEB_HTTPS" }} + https: {{ env "DEX_WEB_HTTPS" }} + {{- if env "DEX_WEB_TLS_KEY" }} + tlsKey: {{ env "DEX_WEB_TLS_KEY" }} + {{- else }} +{{- fail "DEX_WEB_TLS_KEY is required" }} + {{- end }} + {{- if env "DEX_WEB_TLS_CERT" }} + tlsCert: {{ env "DEX_WEB_TLS_CERT" }} + {{- else }} +{{- fail "$DEX_WEB_TLS_CERT is required" }} + {{- end }} +{{- end }} + http: {{ env "DEX_WEB_HTTP" | default "0.0.0.0:5556" }} + + + +{{- if env "DEX_TELEMETRY_HTTP" }} +telemetry: + http: {{ env "DEX_TELEMETRY_HTTP" }} +{{- end }} + +expiry: + deviceRequests: {{ env "DEX_EXPIRY_DEVICE_REQUESTS" | default "5m" }} + signingKeys: {{ env "DEX_EXPIRY_SIGNING_KEYS" | default "6h" }} + idTokens: {{ env "DEX_EXPIRY_ID_TOKENS" | default "24h" }} + authRequests: {{ env "DEX_EXPIRY_AUTH_REQUESTS" | default "24h" }} + +logger: + level: {{ env "DEX_LOGGER_LEVEL" | default "info" }} + format: {{ env "DEX_LOGGER_FORMAT" | default "text" }} + +oauth2: + responseTypes: {{ env "DEX_OAUTH2_RESPONSE_TYPES" | default "[code]" }} + skipApprovalScreen: {{ env "DEX_OAUTH2_SKIP_APPROVAL_SCREEN" | default "false" }} + alwaysShowLoginScreen: {{ env "DEX_OAUTH2_ALWAYS_SHOW_LOGIN_SCREEN" | default "false" }} +{{- if env "DEX_OAUTH2_PASSWORD_CONNECTOR" }} + passwordConnector: {{ env "DEX_OAUTH2_PASSWORD_CONNECTOR" }} +{{- end }} + +enablePasswordDB: {{ env "DEX_ENABLE_PASSWORD_DB" | default "true" }} + +connectors: +{{- if env "DEX_CONNECTORS_ENABLE_MOCK" }} +- type: mockCallback + id: mock + name: Example +{{- end }} diff --git a/go.mod b/go.mod index 8a73117c62..8780b0f21d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/dexidp/dex go 1.15 require ( + github.com/Masterminds/sprig/v3 v3.2.0 github.com/Microsoft/hcsshim v0.8.14 // indirect github.com/beevik/etree v1.1.0 github.com/coreos/go-oidc/v3 v3.0.0 diff --git a/go.sum b/go.sum index b5c0804efc..73f1bc6588 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,12 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.2.0 h1:P1ekkbuU73Ui/wS0nK1HOM37hh4xdfZo485UPf8rc+Y= +github.com/Masterminds/sprig/v3 v3.2.0/go.mod h1:tWhwTbUTndesPNeF0C900vKoq283u6zp4APT9vaF3SI= github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331 h1:3YnB7Hpmh1lPecPE8doMOtYCrMdrpedZOvxfuNES/Vk= @@ -152,6 +158,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -196,6 +204,10 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -237,6 +249,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -244,6 +258,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -311,6 +327,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -325,6 +343,8 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= @@ -375,6 +395,7 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -555,6 +576,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v0.0.0-20181223230014-1083505acf35 h1:zpdCK+REwbk+rqjJmHhiCN6iBIigrZ39glqSF0P3KF0=