Skip to content

Commit

Permalink
Revise setup instruction (#235)
Browse files Browse the repository at this point in the history
  • Loading branch information
int128 authored Feb 12, 2020
1 parent 7ce98c7 commit 42879dc
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 103 deletions.
32 changes: 30 additions & 2 deletions acceptance_test/Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,41 @@
CLUSTER_NAME := kubelogin-acceptance-test
OUTPUT_DIR := $(CURDIR)/output

PATH := $(PATH):$(OUTPUT_DIR)/bin
export PATH
KUBECONFIG := $(OUTPUT_DIR)/kubeconfig.yaml
export KUBECONFIG

# run the login script instead of opening chrome
BROWSER := $(OUTPUT_DIR)/bin/chromelogin
export BROWSER

.PHONY: test
test: build
PATH=$(PATH):$(OUTPUT_DIR)/bin BROWSER=chromelogin KUBECONFIG=$(KUBECONFIG):kubeconfig_oidc.yaml \
kubectl --user=oidc cluster-info
# see the setup instruction
kubectl oidc-login setup \
--oidc-issuer-url=https://dex-server:10443/dex \
--oidc-client-id=YOUR_CLIENT_ID \
--oidc-client-secret=YOUR_CLIENT_SECRET \
--oidc-extra-scope=email \
--certificate-authority=$(OUTPUT_DIR)/ca.crt
# set up the kubeconfig
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1beta1 \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \
--exec-arg=--oidc-issuer-url=https://dex-server:10443/dex \
--exec-arg=--oidc-client-id=YOUR_CLIENT_ID \
--exec-arg=--oidc-client-secret=YOUR_CLIENT_SECRET \
--exec-arg=--oidc-extra-scope=email \
--exec-arg=--certificate-authority=$(OUTPUT_DIR)/ca.crt
# make sure we can access the cluster
kubectl --user=oidc cluster-info
# switch the current context
kubectl config set-context --current --user=oidc
# make sure we can access the cluster
kubectl cluster-info

.PHONY: setup
setup: build dex cluster setup-chrome
Expand Down
25 changes: 0 additions & 25 deletions acceptance_test/kubeconfig_oidc.yaml

This file was deleted.

66 changes: 35 additions & 31 deletions docs/setup.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Kubernetes OpenID Connection authentication

This document guides how to set up the Kubernetes OpenID Connect (OIDC) authentication.
This document guides how to set up Kubernetes OpenID Connect (OIDC) authentication.
Let's see the following steps:

1. Set up the OIDC provider
Expand Down Expand Up @@ -35,7 +35,7 @@ Variable | Value
You can log in with a user of Keycloak.
Make sure you have an administrator role of the Keycloak realm.

Open the Keycloak and create an OIDC client as follows:
Open Keycloak and create an OIDC client as follows:

- Client ID: `YOUR_CLIENT_ID`
- Valid Redirect URLs:
Expand All @@ -52,7 +52,7 @@ You can associate client roles by adding the following mapper:
- Token Claim Name: `groups`
- Add to ID token: on

For example, if you have the `admin` role of the client, you will get a JWT with the claim `{"groups": ["kubernetes:admin"]}`.
For example, if you have `admin` role of the client, you will get a JWT with the claim `{"groups": ["kubernetes:admin"]}`.

Replace the following variables in the later sections.

Expand All @@ -72,7 +72,7 @@ Open [GitHub OAuth Apps](https://github.com/settings/developers) and create an a
- Homepage URL: `https://dex.example.com`
- Authorization callback URL: `https://dex.example.com/callback`

Deploy the [dex](https://github.com/dexidp/dex) with the following config:
Deploy [Dex](https://github.com/dexidp/dex) with the following config:

```yaml
issuer: https://dex.example.com
Expand Down Expand Up @@ -138,13 +138,20 @@ kubectl oidc-login setup \
--oidc-client-secret=YOUR_CLIENT_SECRET
```

It will open the browser and you can log in to the provider.
Then it will show the instruction.
It launches the browser and navigates to `http://localhost:8000`.
Please log in to the provider.

You can set extra options, for example, extra scope or CA certificate.
See also the full options.

```sh
kubectl oidc-login setup --help
```


## 3. Bind a cluster role

In this tutorial, bind the `cluster-admin` role to you.
Here bind `cluster-admin` role to you.
Apply the following manifest:

```yaml
Expand All @@ -170,14 +177,14 @@ As well as you can create a custom cluster role and bind it.

## 4. Set up the Kubernetes API server

Add the following options to the kube-apiserver:
Add the following flags to kube-apiserver:

```
--oidc-issuer-url=ISSUER_URL
--oidc-client-id=YOUR_CLIENT_ID
```

See [OpenID Connect Tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) for details.
See [Kubernetes Authenticating: OpenID Connect Tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) for the all flags.

If you are using [kops](https://github.com/kubernetes/kops), run `kops edit cluster` and append the following settings:

Expand All @@ -200,35 +207,32 @@ If you are using [kube-aws](https://github.com/kubernetes-incubator/kube-aws), a

## 5. Set up the kubeconfig

Add the following user to the kubeconfig:
Add `oidc` user to the kubeconfig.

```yaml
users:
- name: oidc
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: kubectl
args:
- oidc-login
- get-token
- --oidc-issuer-url=ISSUER_URL
- --oidc-client-id=YOUR_CLIENT_ID
- --oidc-client-secret=YOUR_CLIENT_SECRET
```sh
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1beta1 \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \
--exec-arg=--oidc-issuer-url=ISSUER_URL \
--exec-arg=--oidc-client-id=YOUR_CLIENT_ID \
--exec-arg=--oidc-client-secret=YOUR_CLIENT_SECRET
```

You can share the kubeconfig to your team members for on-boarding.


## 6. Verify cluster access

Make sure you can access the Kubernetes cluster.

```sh
kubectl --user=oidc cluster-info
```
% kubectl get nodes
Open http://localhost:8000 for authentication
You got a valid token until 2019-05-16 22:03:13 +0900 JST
NAME STATUS ROLES AGE VERSION
ip-1-2-3-4.us-west-2.compute.internal Ready node 21d v1.9.6
ip-1-2-3-5.us-west-2.compute.internal Ready node 20d v1.9.6

You can switch the current context to oidc.

```sh
kubectl config set-context --current --user=oidc
```

You can share the kubeconfig to your team members for on-boarding.
9 changes: 6 additions & 3 deletions pkg/adaptors/cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ type setupOptions struct {
ClientID string
ClientSecret string
ExtraScopes []string
CertificateAuthority string
CACertFilename string
CACertData string
SkipTLSVerify bool
authenticationOptions authenticationOptions
}
Expand All @@ -26,7 +27,8 @@ func (o *setupOptions) register(f *pflag.FlagSet) {
f.StringVar(&o.ClientID, "oidc-client-id", "", "Client ID of the provider")
f.StringVar(&o.ClientSecret, "oidc-client-secret", "", "Client secret of the provider")
f.StringSliceVar(&o.ExtraScopes, "oidc-extra-scope", nil, "Scopes to request to the provider")
f.StringVar(&o.CertificateAuthority, "certificate-authority", "", "Path to a cert file for the certificate authority")
f.StringVar(&o.CACertFilename, "certificate-authority", "", "Path to a cert file for the certificate authority")
f.StringVar(&o.CACertData, "certificate-authority-data", "", "Base64 encoded data for the certificate authority")
f.BoolVar(&o.SkipTLSVerify, "insecure-skip-tls-verify", false, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
o.authenticationOptions.register(f)
}
Expand All @@ -51,7 +53,8 @@ func (cmd *Setup) New(ctx context.Context) *cobra.Command {
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,
ExtraScopes: o.ExtraScopes,
CACertFilename: o.CertificateAuthority,
CACertFilename: o.CACertFilename,
CACertData: o.CACertData,
SkipTLSVerify: o.SkipTLSVerify,
GrantOptionSet: grantOptionSet,
}
Expand Down
67 changes: 43 additions & 24 deletions pkg/usecases/setup/stage2.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ import (
)

var stage2Tpl = template.Must(template.New("").Parse(`
## 3. Bind a role
## 2. Verify authentication
Run the following command:
You got a token with the following claims:
{{- range $k, $v := .Claims }}
{{ $k }}={{ $v }}
{{- end }}
## 3. Bind a cluster role
Apply the following manifest:
kubectl apply -f - <<-EOF
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
Expand All @@ -26,7 +33,6 @@ Run the following command:
subjects:
- kind: User
name: {{ .IssuerURL }}#{{ .Subject }}
EOF
## 4. Set up the Kubernetes API server
Expand All @@ -37,25 +43,32 @@ Add the following options to the kube-apiserver:
## 5. Set up the kubeconfig
Add the following user to the kubeconfig:
users:
- name: google
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: kubectl
args:
- oidc-login
- get-token
Run the following command:
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1beta1 \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \
{{- range .Args }}
- {{ . }}
--exec-arg={{ . }}
{{- end }}
Run kubectl and verify cluster access.
## 6. Verify cluster access
Make sure you can access the Kubernetes cluster.
kubectl --user=oidc get nodes
You can switch the default context to oidc.
kubectl config set-context --current --user=oidc
You can share the kubeconfig to your team members for on-boarding.
`))

type stage2Vars struct {
Claims map[string]string
IssuerURL string
ClientID string
Args []string
Expand All @@ -68,18 +81,24 @@ type Stage2Input struct {
ClientID string
ClientSecret string
ExtraScopes []string // optional
CACertFilename string // If set, use the CA cert
CACertFilename string // optional
CACertData string // optional
SkipTLSVerify bool
ListenAddressArgs []string // non-nil if set by the command arg
GrantOptionSet authentication.GrantOptionSet
}

func (u *Setup) DoStage2(ctx context.Context, in Stage2Input) error {
u.Logger.Printf(`## 2. Verify authentication`)
u.Logger.Printf("authentication in progress...")
certPool := u.NewCertPool()
if in.CACertFilename != "" {
if err := certPool.AddFile(in.CACertFilename); err != nil {
return xerrors.Errorf("could not load the certificate: %w", err)
return xerrors.Errorf("could not load the certificate file: %w", err)
}
}
if in.CACertData != "" {
if err := certPool.AddBase64Encoded(in.CACertData); err != nil {
return xerrors.Errorf("could not load the certificate data: %w", err)
}
}
out, err := u.Authentication.Do(ctx, authentication.Input{
Expand All @@ -94,12 +113,9 @@ func (u *Setup) DoStage2(ctx context.Context, in Stage2Input) error {
if err != nil {
return xerrors.Errorf("error while authentication: %w", err)
}
u.Logger.Printf("You got the following claims in the token:")
for k, v := range out.IDTokenClaims.Pretty {
u.Logger.Printf("\t%s=%s", k, v)
}

v := stage2Vars{
Claims: out.IDTokenClaims.Pretty,
IssuerURL: in.IssuerURL,
ClientID: in.ClientID,
Args: makeCredentialPluginArgs(in),
Expand All @@ -126,6 +142,9 @@ func makeCredentialPluginArgs(in Stage2Input) []string {
if in.CACertFilename != "" {
args = append(args, "--certificate-authority="+in.CACertFilename)
}
if in.CACertData != "" {
args = append(args, "--certificate-authority-data="+in.CACertData)
}
if in.SkipTLSVerify {
args = append(args, "--insecure-skip-tls-verify")
}
Expand Down
Loading

0 comments on commit 42879dc

Please sign in to comment.