Skip to content

Commit 3f4bdbe

Browse files
committed
feat: add oidc authentication
1 parent 854087c commit 3f4bdbe

File tree

6 files changed

+122
-44
lines changed

6 files changed

+122
-44
lines changed

docs/book/src/commands/use_oidc.md

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ kconnect use oidc [flags]
6767
--oidc-use-pkce string if use pkce
6868
--password string The password to use for authentication
6969
--set-current Sets the current context in the kubeconfig to the selected cluster (default true)
70+
--skip-ssl string flag to skip ssl for calling config url
7071
--username string The username used for authentication
7172
```
7273
@@ -94,6 +95,7 @@ Use `--idp-protocol=oidc`
9495
--oidc-client-secret string oidc client secret
9596
--oidc-server string oidc server url
9697
--oidc-use-pkce string if use pkce
98+
--skip-ssl string flag to skip ssl for calling config url
9799
```
98100
99101
### SEE ALSO

pkg/oidc/config.go

+14
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ limitations under the License.
1717
package oidc
1818

1919
import (
20+
"fmt"
21+
2022
"github.com/fidelity/kconnect/pkg/config"
23+
"github.com/fidelity/kconnect/pkg/prompt"
2124
)
2225

2326
const (
@@ -39,6 +42,8 @@ const (
3942
ConfigUrlConfigDescription = "configuration endpoint"
4043
CaCertConfigItem = "ca-cert"
4144
CaCertConfigDescription = "ca cert for configuration url"
45+
SkipTlsVerifyConfigItem = "skip-ssl"
46+
SkipTlsVerifyDescription = "flag to skip ssl for calling config url"
4247
)
4348

4449
// SharedConfig will return shared configuration items for OIDC based cluster and identity providers
@@ -52,6 +57,15 @@ func SharedConfig() config.ConfigurationSet {
5257
cs.String(ClusterAuthConfigItem, "", ClusterAuthConfigDescription) //nolint: errcheck
5358
cs.String(ConfigUrlConfigItem, "", ConfigUrlConfigDescription) //nolint: errcheck
5459
cs.String(CaCertConfigItem, "", CaCertConfigDescription) //nolint: errcheck
60+
cs.String(SkipTlsVerifyConfigItem, "", SkipTlsVerifyDescription) //nolint: errcheck
5561

5662
return cs
5763
}
64+
65+
func ReadUserInput(key string, msg string) (string, error) {
66+
userInput, err := prompt.Input(key, msg, false)
67+
if userInput == "" || err != nil {
68+
return userInput, fmt.Errorf("error reading input for %s", key)
69+
}
70+
return userInput, nil
71+
}

pkg/plugins/discovery/oidc/config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func (p *oidcClusterProvider) GetConfig(ctx context.Context, input *discovery.Ge
5959
args := []string{
6060
"oidc-login",
6161
"get-token",
62-
"--oidc-issuer-url=oidc-server",
62+
"--oidc-issuer-url=" + oidcID.OidcServer,
6363
"--oidc-client-id=" + oidcID.OidcId,
6464
}
6565

pkg/plugins/discovery/oidc/provider.go

+5-37
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ import (
2222

2323
"github.com/fidelity/kconnect/pkg/config"
2424
"github.com/fidelity/kconnect/pkg/oidc"
25-
"github.com/fidelity/kconnect/pkg/prompt"
2625
"github.com/fidelity/kconnect/pkg/provider"
2726
"github.com/fidelity/kconnect/pkg/provider/common"
2827
"github.com/fidelity/kconnect/pkg/provider/discovery"
2928
"github.com/fidelity/kconnect/pkg/provider/identity"
3029
"github.com/fidelity/kconnect/pkg/provider/registry"
30+
"github.com/fidelity/kconnect/pkg/utils"
3131
"go.uber.org/zap"
3232
)
3333

@@ -123,48 +123,24 @@ func (p *oidcClusterProvider) logParameters() {
123123
// For required parameter, if not exists in default config file or config url, read user input.
124124
func (p *oidcClusterProvider) readRequiredFields() error {
125125

126-
if p.identity.OidcId == "" {
127-
value, err := readUserInput(oidc.OidcIdConfigItem, oidc.OidcIdConfigDescription)
128-
if err != nil {
129-
return err
130-
}
131-
p.identity.OidcId = value
132-
}
133-
134-
if p.identity.OidcServer == "" {
135-
value, err := readUserInput(oidc.OidcServerConfigItem, oidc.OidcServerConfigDescription)
136-
if err != nil {
137-
return err
138-
}
139-
p.identity.OidcServer = value
140-
}
141-
142-
if p.identity.UsePkce != True && p.identity.OidcSecret == "" {
143-
value, err := readUserInput(oidc.OidcSecretConfigItem, oidc.OidcSecretConfigDescription)
144-
if err != nil {
145-
return err
146-
}
147-
p.identity.OidcSecret = value
148-
}
149-
150126
if p.config.ClusterUrl == "" {
151-
value, err := readUserInput(oidc.ClusterUrlConfigItem, oidc.ClusterUrlConfigDescription)
127+
value, err := oidc.ReadUserInput(oidc.ClusterUrlConfigItem, oidc.ClusterUrlConfigDescription)
152128
if err != nil {
153129
return err
154130
}
155131
p.config.ClusterUrl = value
156132
}
157133

158134
if p.config.ClusterAuth == "" {
159-
value, err := readUserInput(oidc.ClusterAuthConfigItem, oidc.ClusterAuthConfigDescription)
135+
value, err := oidc.ReadUserInput(oidc.ClusterAuthConfigItem, oidc.ClusterAuthConfigDescription)
160136
if err != nil {
161137
return err
162138
}
163139
p.config.ClusterAuth = value
164140
}
165141

166142
if *p.config.ClusterID == "" {
167-
value, err := readUserInput(oidc.ClusterIdConfigItem, oidc.ClusterIdConfigDescription)
143+
value, err := oidc.ReadUserInput(oidc.ClusterIdConfigItem, oidc.ClusterIdConfigDescription)
168144
if err != nil {
169145
return err
170146
}
@@ -175,20 +151,12 @@ func (p *oidcClusterProvider) readRequiredFields() error {
175151

176152
}
177153

178-
func readUserInput(key string, msg string) (string, error) {
179-
userInput, err := prompt.Input(key, msg, false)
180-
if userInput == "" || err != nil {
181-
return userInput, fmt.Errorf("error reading input for %s", key)
182-
}
183-
return userInput, nil
184-
}
185-
186154
func (p *oidcClusterProvider) ListPreReqs() []*provider.PreReq {
187155
return []*provider.PreReq{}
188156
}
189157

190158
func (p *oidcClusterProvider) CheckPreReqs() error {
191-
return nil
159+
return utils.CheckKubectlOidcLoginPrereq()
192160
}
193161

194162
// ConfigurationItems returns the configuration items for this provider

pkg/plugins/identity/oidc/provider.go

+90-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"log"
2323
"net/http"
2424
"os"
25+
"os/exec"
2526
"strings"
2627

2728
"go.uber.org/zap"
@@ -38,6 +39,7 @@ import (
3839

3940
const (
4041
ProviderName = "oidc"
42+
True = "true"
4143
)
4244

4345
func init() {
@@ -95,11 +97,74 @@ func (p *oidcIdentityProvider) Authenticate(ctx context.Context, input *identity
9597
UsePkce: cfg.UsePkce,
9698
}
9799

100+
ids, err := p.readRequiredFields(*id)
101+
if err != nil {
102+
return nil, err
103+
}
104+
105+
if err = executeOidcLogin(ids); err != nil {
106+
return nil, err
107+
}
108+
98109
return &identity.AuthenticateOutput{
99-
Identity: id,
110+
Identity: &ids,
100111
}, nil
101112
}
102113

114+
func executeOidcLogin(id oidc.Identity) error {
115+
116+
args := []string{
117+
"oidc-login",
118+
"get-token",
119+
"--oidc-issuer-url=" + id.OidcServer,
120+
"--oidc-client-id=" + id.OidcId,
121+
}
122+
123+
if id.UsePkce == True {
124+
args = append(args, "--oidc-use-pkce")
125+
} else {
126+
args = append(args, "--oidc-client-secret="+id.OidcSecret)
127+
}
128+
args = append(args, "--insecure-skip-tls-verify")
129+
130+
cmd := exec.Command("kubectl", args...)
131+
_, err := cmd.Output()
132+
if err != nil {
133+
return fmt.Errorf("error executing kubectl oidc-login: %w", err)
134+
}
135+
return nil
136+
}
137+
138+
func (p *oidcIdentityProvider) readRequiredFields(id oidc.Identity) (oidc.Identity, error) {
139+
140+
if id.OidcId == "" {
141+
value, err := oidc.ReadUserInput(oidc.OidcIdConfigItem, oidc.OidcIdConfigDescription)
142+
if err != nil {
143+
return id, err
144+
}
145+
id.OidcId = value
146+
}
147+
148+
if id.OidcServer == "" {
149+
value, err := oidc.ReadUserInput(oidc.OidcServerConfigItem, oidc.OidcServerConfigDescription)
150+
if err != nil {
151+
return id, err
152+
}
153+
id.OidcServer = value
154+
}
155+
156+
if id.UsePkce != True && id.OidcSecret == "" {
157+
value, err := oidc.ReadUserInput(oidc.OidcSecretConfigItem, oidc.OidcSecretConfigDescription)
158+
if err != nil {
159+
return id, err
160+
}
161+
id.OidcSecret = value
162+
}
163+
164+
return id, nil
165+
166+
}
167+
103168
func (p *oidcIdentityProvider) getConfigFromUrl(configSet config.ConfigurationSet) {
104169
if configSet.Get("config-url") != nil {
105170
config := configSet.Get("config-url").Value
@@ -113,13 +178,32 @@ func (p *oidcIdentityProvider) getConfigFromUrl(configSet config.ConfigurationSe
113178
}
114179

115180
func readConfigs(p *oidcIdentityProvider, configSet config.ConfigurationSet, configValue string) {
116-
if configSet.Get("ca-cert") != nil {
117-
caCert := configSet.Get("ca-cert").Value
118-
if caCert != nil {
119-
SetTransport(caCert.(string))
181+
skipSsl := false
182+
if configSet.Get("skip-ssl") != nil {
183+
skip := configSet.Get("skip-ssl").Value
184+
if skip != nil {
185+
if skip.(string) == True {
186+
skipSsl = true
187+
}
120188
}
121-
} else {
189+
}
190+
if skipSsl {
122191
SetTransport("")
192+
} else {
193+
readCa := false
194+
if configSet.Get("ca-cert") != nil {
195+
caCert := configSet.Get("ca-cert").Value
196+
if caCert != nil {
197+
if caCert.(string) != "" {
198+
readCa = true
199+
SetTransport(caCert.(string))
200+
}
201+
}
202+
}
203+
if !readCa {
204+
p.logger.Errorf("CA cert is required to call the config url.")
205+
return
206+
}
123207
}
124208
kclient := khttp.NewHTTPClient()
125209
res, err := kclient.Get(configValue, nil)

pkg/utils/prerequisites.go

+10
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,13 @@ func CheckKubeloginPrereq() error {
7373
}
7474
return nil
7575
}
76+
77+
func CheckKubectlOidcLoginPrereq() error {
78+
79+
cmd := exec.Command("kubectl", "oidc-login", "version")
80+
_, err := cmd.Output()
81+
if err != nil {
82+
return fmt.Errorf("error finding kubectl oidc-login: %w", err)
83+
}
84+
return nil
85+
}

0 commit comments

Comments
 (0)