github.com/argoproj/argo-cd/v3@v3.2.1/util/dex/config.go (about) 1 package dex 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 8 "sigs.k8s.io/yaml" 9 10 "github.com/argoproj/argo-cd/v3/common" 11 "github.com/argoproj/argo-cd/v3/util/settings" 12 13 log "github.com/sirupsen/logrus" 14 ) 15 16 func GenerateDexConfigYAML(argocdSettings *settings.ArgoCDSettings, disableTLS bool) ([]byte, error) { 17 if !argocdSettings.IsDexConfigured() { 18 return nil, nil 19 } 20 redirectURL, err := argocdSettings.RedirectURL() 21 if err != nil { 22 return nil, fmt.Errorf("failed to infer redirect url from config: %w", err) 23 } 24 var dexCfg map[string]any 25 err = yaml.Unmarshal([]byte(argocdSettings.DexConfig), &dexCfg) 26 if err != nil { 27 return nil, fmt.Errorf("failed to unmarshal dex.config from configmap: %w", err) 28 } 29 dexCfg["issuer"] = argocdSettings.IssuerURL() 30 dexCfg["storage"] = map[string]any{ 31 "type": "memory", 32 } 33 if disableTLS { 34 dexCfg["web"] = map[string]any{ 35 "http": "0.0.0.0:5556", 36 } 37 } else { 38 dexCfg["web"] = map[string]any{ 39 "https": "0.0.0.0:5556", 40 "tlsCert": "/tmp/tls.crt", 41 "tlsKey": "/tmp/tls.key", 42 } 43 } 44 45 if loggerCfg, found := dexCfg["logger"].(map[string]any); found { 46 if _, found := loggerCfg["level"]; !found { 47 loggerCfg["level"] = slogLevelFromLogrus(os.Getenv(common.EnvLogLevel)) 48 } 49 if _, found := loggerCfg["format"]; !found { 50 loggerCfg["format"] = os.Getenv(common.EnvLogFormat) 51 } 52 } else { 53 dexCfg["logger"] = map[string]any{ 54 "level": slogLevelFromLogrus(os.Getenv(common.EnvLogLevel)), 55 "format": os.Getenv(common.EnvLogFormat), 56 } 57 } 58 59 dexCfg["grpc"] = map[string]any{ 60 "addr": "0.0.0.0:5557", 61 } 62 dexCfg["telemetry"] = map[string]any{ 63 "http": "0.0.0.0:5558", 64 } 65 66 if oauth2Cfg, found := dexCfg["oauth2"].(map[string]any); found { 67 if _, found := oauth2Cfg["skipApprovalScreen"].(bool); !found { 68 oauth2Cfg["skipApprovalScreen"] = true 69 } 70 } else { 71 dexCfg["oauth2"] = map[string]any{ 72 "skipApprovalScreen": true, 73 } 74 } 75 76 additionalRedirectURLs, err := argocdSettings.RedirectAdditionalURLs() 77 if err != nil { 78 return nil, fmt.Errorf("failed to infer additional redirect urls from config: %w", err) 79 } 80 argoCDStaticClient := map[string]any{ 81 "id": common.ArgoCDClientAppID, 82 "name": common.ArgoCDClientAppName, 83 "secret": argocdSettings.DexOAuth2ClientSecret(), 84 "redirectURIs": append([]string{redirectURL}, additionalRedirectURLs...), 85 } 86 argoCDPKCEStaticClient := map[string]any{ 87 "id": "argo-cd-pkce", 88 "name": "Argo CD PKCE", 89 "redirectURIs": []string{ 90 "http://localhost:4000/auth/callback", 91 }, 92 "public": true, 93 } 94 argoCDCLIStaticClient := map[string]any{ 95 "id": common.ArgoCDCLIClientAppID, 96 "name": common.ArgoCDCLIClientAppName, 97 "public": true, 98 "redirectURIs": []string{ 99 "http://localhost", 100 "http://localhost:8085/auth/callback", 101 }, 102 } 103 104 staticClients, ok := dexCfg["staticClients"].([]any) 105 if ok { 106 dexCfg["staticClients"] = append([]any{argoCDStaticClient, argoCDCLIStaticClient, argoCDPKCEStaticClient}, staticClients...) 107 } else { 108 dexCfg["staticClients"] = []any{argoCDStaticClient, argoCDCLIStaticClient, argoCDPKCEStaticClient} 109 } 110 111 dexRedirectURL, err := argocdSettings.DexRedirectURL() 112 if err != nil { 113 return nil, err 114 } 115 connectors, ok := dexCfg["connectors"].([]any) 116 if !ok { 117 return nil, errors.New("malformed Dex configuration found") 118 } 119 for i, connectorIf := range connectors { 120 connector, ok := connectorIf.(map[string]any) 121 if !ok { 122 return nil, errors.New("malformed Dex configuration found") 123 } 124 connectorType := connector["type"].(string) 125 if !needsRedirectURI(connectorType) { 126 continue 127 } 128 connectorCfg, ok := connector["config"].(map[string]any) 129 if !ok { 130 return nil, errors.New("malformed Dex configuration found") 131 } 132 connectorCfg["redirectURI"] = dexRedirectURL 133 connector["config"] = connectorCfg 134 connectors[i] = connector 135 } 136 dexCfg["connectors"] = connectors 137 dexCfg = settings.ReplaceMapSecrets(dexCfg, argocdSettings.Secrets) 138 return yaml.Marshal(dexCfg) 139 } 140 141 // needsRedirectURI returns whether or not the given connector type needs a redirectURI 142 // Update this list as necessary, as new connectors are added 143 // https://dexidp.io/docs/connectors/ 144 func needsRedirectURI(connectorType string) bool { 145 switch connectorType { 146 case "oidc", "saml", "microsoft", "linkedin", "gitlab", "github", "bitbucket-cloud", "openshift", "gitea", "google", "oauth": 147 return true 148 } 149 return false 150 } 151 152 func slogLevelFromLogrus(level string) string { 153 logrusLevel, err := log.ParseLevel(level) 154 if err != nil { 155 return level 156 } 157 158 switch logrusLevel { 159 case log.DebugLevel, log.TraceLevel: 160 return "DEBUG" 161 case log.InfoLevel: 162 return "INFO" 163 case log.WarnLevel: 164 return "WARN" 165 case log.ErrorLevel, log.FatalLevel, log.PanicLevel: 166 return "ERROR" 167 } 168 // return the logrus level and let slog parse it 169 return level 170 }