From d9b8d99fae22c88d23dae1bc43534573c1d437a7 Mon Sep 17 00:00:00 2001 From: Hidetake Iwata Date: Tue, 27 Aug 2019 11:51:48 +0900 Subject: [PATCH] Refactor docs (#138) * Refactor: extract standalone-mode.md * Refactor: remove diagram * Refactor: remove DESIGN.md * Refactor: change README.md --- DESIGN.md | 47 --------- Makefile | 5 - README.md | 225 +++++----------------------------------- docs/authn.png | Bin 66893 -> 0 bytes docs/authn.seqdiag | 16 --- docs/standalone-mode.md | 168 ++++++++++++++++++++++++++++++ 6 files changed, 193 insertions(+), 268 deletions(-) delete mode 100644 DESIGN.md delete mode 100644 docs/authn.png delete mode 100644 docs/authn.seqdiag create mode 100644 docs/standalone-mode.md diff --git a/DESIGN.md b/DESIGN.md deleted file mode 100644 index c13419c..0000000 --- a/DESIGN.md +++ /dev/null @@ -1,47 +0,0 @@ -# Design of kubelogin - -This explains design of kubelogin. - -## Use cases - -Kubelogin is a command line tool and designed to run as both a standalone command and a kubectl plugin. - -It respects the following flags, commonly used in kubectl: - -``` - --kubeconfig string Path to the kubeconfig file - --context string The name of the kubeconfig context to use - --user string The name of the kubeconfig user to use. Prior to --context - --certificate-authority string Path to a cert file for the certificate authority - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - -v, --v int If set to 1 or greater, it shows debug log -``` - -As well as it respects the environment variable `KUBECONFIG`. - - -### Login by the command - -TODO - - -## Architecture - -Kubelogin consists of the following layers: - -- `usecases`: This provides the use-cases. -- `adaptor`: This provides external access and converts objects between the use-cases and external system. - - -### Use-cases - -This provides the use-cases mentioned in the previous section. - -This layer should not contain external access such as HTTP requests and system calls. - - -### Adaptor - -This provides external access such as command line interface and HTTP requests. - - diff --git a/Makefile b/Makefile index 9cd53c7..9c80011 100644 --- a/Makefile +++ b/Makefile @@ -20,11 +20,6 @@ $(TARGET_PLUGIN): $(TARGET) run: $(TARGET_PLUGIN) -PATH=.:$(PATH) kubectl oidc-login --help -diagram: docs/authn.png - -%.png: %.seqdiag - seqdiag -a -f /Library/Fonts/Verdana.ttf $< - dist: VERSION=$(CIRCLE_TAG) goxzst -d dist/gh/ -o "$(TARGET)" -t "kubelogin.rb oidc-login.yaml" -- -ldflags "$(LDFLAGS)" mv dist/gh/kubelogin.rb dist/ diff --git a/README.md b/README.md index f812fd5..d579787 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ Then kubelogin gets a token from the provider and kubectl access Kubernetes APIs ## Getting Started -You can install the latest release from [Homebrew](https://brew.sh/), [Krew](https://github.com/kubernetes-sigs/krew) or [GitHub Releases](https://github.com/int128/kubelogin/releases) as follows: +### Setup + +Install the latest release from [Homebrew](https://brew.sh/), [Krew](https://github.com/kubernetes-sigs/krew) or [GitHub Releases](https://github.com/int128/kubelogin/releases) as follows: ```sh # Homebrew @@ -24,25 +26,16 @@ unzip kubelogin_linux_amd64.zip ln -s kubelogin kubectl-oidc_login ``` -You need to configure the OIDC provider, Kubernetes API server, kubeconfig and role binding. +You need to configure the OIDC provider, Kubernetes API server and role binding. See the following documents for more: - [Getting Started with Keycloak](docs/keycloak.md) - [Getting Started with dex and GitHub](docs/dex.md) - [Getting Started with Google Identity Platform](docs/google.md) -You can run kubelogin as the following methods: - -- Credential plugin mode (recommended) -- Standalone mode - - -### Credential plugin mode - -You can run kubelogin as a [client-go credential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins). -This provides transparent login without manually running `kubelogin` command. - -Configure the kubeconfig like: +Configure the kubeconfig to run kubelogin as a [client-go credential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins). +It provides transparent login without manually running kubelogin command. +For example, ```yaml users: @@ -59,6 +52,8 @@ users: - --oidc-client-secret=YOUR_CLIENT_SECRET ``` +### Run + Run kubectl. ```sh @@ -89,90 +84,17 @@ If the refresh token has expired, kubelogin will perform reauthentication. You can log out by removing the token cache directory (default `~/.kube/cache/oidc-login`). Kubelogin will perform authentication if the token cache file does not exist. - ### Standalone mode -You can run kubelogin as a standalone command. -In this method, you need to manually run the command before running kubectl. - -Configure the kubeconfig like: - -```yaml -- name: keycloak - user: - auth-provider: - config: - client-id: YOUR_CLIENT_ID - client-secret: YOUR_CLIENT_SECRET - idp-issuer-url: https://issuer.example.com - name: oidc -``` - -Run kubelogin: - -```sh -kubelogin - -# or run as a kubectl plugin -kubectl oidc-login -``` - -It automatically opens the browser and you can log in to the provider. - -keycloak-login - -After authentication, kubelogin writes the ID token and refresh token to the kubeconfig. - -``` -% kubelogin -Open http://localhost:8000 for authentication -You got a valid token until 2019-05-18 10:28:51 +0900 JST -Updated ~/.kubeconfig -``` - -Now you can access the cluster. - -``` -% kubectl get pods -NAME READY STATUS RESTARTS AGE -echoserver-86c78fdccd-nzmd5 1/1 Running 0 26d -``` - -Your kubeconfig looks like: - -```yaml -users: -- name: keycloak - user: - auth-provider: - config: - client-id: YOUR_CLIENT_ID - client-secret: YOUR_CLIENT_SECRET - idp-issuer-url: https://issuer.example.com - id-token: ey... # kubelogin will add or update the ID token here - refresh-token: ey... # kubelogin will add or update the refresh token here - name: oidc -``` - -If the ID token is valid, kubelogin does nothing. - -``` -% kubelogin -You already have a valid token until 2019-05-18 10:28:51 +0900 JST -``` - -If the ID token has expired, kubelogin will refresh the token using the refresh token in the kubeconfig. -If the refresh token has expired, kubelogin will proceed the authentication. +As well as you can update the ID token in the kubeconfig by running the command. +See [standalone mode](docs/standalone-mode.md) for more. -## Configuration +## Usage This document is for the development version. If you are looking for a specific version, see [the release tags](https://github.com/int128/kubelogin/tags). - -### Credential plugin mode - Kubelogin supports the following options: ``` @@ -198,7 +120,9 @@ Flags: -h, --help help for get-token ``` -#### Extra scopes +See also the options in [standalone mode](docs/standalone-mode.md). + +### Extra scopes You can set the extra scopes to request to the provider by `--oidc-extra-scope`. @@ -207,110 +131,14 @@ You can set the extra scopes to request to the provider by `--oidc-extra-scope`. - --oidc-extra-scope=profile ``` -#### CA Certificates +### CA Certificates -You can use your self-signed certificates for the provider. +You can use your self-signed certificate for the provider. ```yaml - --certificate-authority=/home/user/.kube/keycloak-ca.pem ``` - -### Standalone mode - -Kubelogin supports the following options: - -``` -% kubelogin -h -Login to the OpenID Connect provider and update the kubeconfig - -Usage: - kubelogin [flags] - kubelogin [command] - -Examples: - # Login to the provider using the authorization code flow. - kubelogin - - # Login to the provider using the resource owner password credentials flow. - kubelogin --username USERNAME --password PASSWORD - - # Run as a credential plugin. - kubelogin get-token --oidc-issuer-url=https://issuer.example.com - -Available Commands: - get-token Run as a kubectl credential plugin - help Help about any command - version Print the version information - -Flags: - --kubeconfig string Path to the kubeconfig file - --context string The name of the kubeconfig context to use - --user string The name of the kubeconfig user to use. Prior to --context - --certificate-authority string Path to a cert file for the certificate authority - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - -v, --v int If set to 1 or greater, it shows debug log - --listen-port ints Port to bind to the local server. If multiple ports are given, it will try the ports in order (default [8000,18000]) - --skip-open-browser If true, it does not open the browser on authentication - --username string If set, perform the resource owner password credentials grant - --password string If set, use the password instead of asking it - -h, --help help for kubelogin -``` - -#### Kubeconfig - -You can set path to the kubeconfig file by the option or the environment variable just like kubectl. -It defaults to `~/.kube/config`. - -```sh -# by the option -kubelogin --kubeconfig /path/to/kubeconfig - -# by the environment variable -KUBECONFIG="/path/to/kubeconfig1:/path/to/kubeconfig2" kubelogin -``` - -If you set multiple files, kubelogin will find the file which has the current authentication (i.e. `user` and `auth-provider`) and write a token to it. - -Kubelogin supports the following keys of `auth-provider` in a kubeconfig. -See [kubectl authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#using-kubectl) for more. - -Key | Direction | Value -----|-----------|------ -`idp-issuer-url` | Read (Mandatory) | Issuer URL of the provider. -`client-id` | Read (Mandatory) | Client ID of the provider. -`client-secret` | Read (Mandatory) | Client Secret of the provider. -`idp-certificate-authority` | Read | CA certificate path of the provider. -`idp-certificate-authority-data` | Read | Base64 encoded CA certificate of the provider. -`extra-scopes` | Read | Scopes to request to the provider (comma separated). -`id-token` | Write | ID token got from the provider. -`refresh-token` | Write | Refresh token got from the provider. - -#### Extra scopes - -You can set the extra scopes to request to the provider by `extra-scopes` in the kubeconfig. - -```sh -kubectl config set-credentials keycloak --auth-provider-arg extra-scopes=email -``` - -Currently kubectl does not accept multiple scopes, so you need to edit the kubeconfig as like: - -```sh -kubectl config set-credentials keycloak --auth-provider-arg extra-scopes=SCOPES -sed -i '' -e s/SCOPES/email,profile/ $KUBECONFIG -``` - -#### CA Certificates - -You can use your self-signed certificates for the provider. - -```sh -kubectl config set-credentials keycloak \ - --auth-provider-arg idp-certificate-authority=$HOME/.kube/keycloak-ca.pem -``` - - ### HTTP Proxy You can set the following environment variables if you are behind a proxy: `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY`. @@ -331,15 +159,11 @@ You need to register the following redirect URIs to the provider: You can change the ports by the option: -```sh -# run as a standalone command -kubelogin --listen-port 12345 --listen-port 23456 - -# run as a credential plugin -kubelogin get-token --listen-port 12345 --listen-port 23456 +```yaml + - --listen-port 12345 + - --listen-port 23456 ``` - #### Resource owner password credentials grant flow As well as you can use the resource owner password credentials grant flow. @@ -348,11 +172,12 @@ Most OIDC providers do not support this flow. You can pass the username and password: -``` -% kubelogin --username USER --password PASS +```yaml + - --username USERNAME + - --password PASSWORD ``` -or use the password prompt: +If the password is not set, kubelogin will show the prompt. ``` % kubelogin --username USER @@ -360,7 +185,7 @@ Password: ``` -## Related topics +## Related works ### Kubernetes Dashboard diff --git a/docs/authn.png b/docs/authn.png deleted file mode 100644 index 564c52b103a30bd0112bb6cc8f92310e7d8d266f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66893 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 kubelogin [label = "execute"]; - kubelogin -> Browser [label = "open"]; - Browser -> Provider [label = "authentication request"]; - Browser <-- Provider [label = "redirect"]; - User -> Browser [label = "enter credentials"]; - Browser -> Provider [label = "credentials"]; - Browser <-- Provider [label = "authentication response"]; - User <-- Browser [label = "success"]; - kubelogin <-- Browser [label = "close"]; - kubelogin -> Provider [label = "token request"]; - kubelogin <-- Provider [label = "token response"]; - kubelogin -> kubeconfig [label = "write token"]; - kubelogin <-- kubeconfig; - User <-- kubelogin; -} diff --git a/docs/standalone-mode.md b/docs/standalone-mode.md new file mode 100644 index 0000000..ec49b08 --- /dev/null +++ b/docs/standalone-mode.md @@ -0,0 +1,168 @@ +# Standalone mode + +You can run kubelogin as a standalone command. +In this mode, you need to manually run the command before running kubectl. + +Configure the kubeconfig like: + +```yaml +- name: keycloak + user: + auth-provider: + config: + client-id: YOUR_CLIENT_ID + client-secret: YOUR_CLIENT_SECRET + idp-issuer-url: https://issuer.example.com + name: oidc +``` + +Run kubelogin: + +```sh +kubelogin + +# or run as a kubectl plugin +kubectl oidc-login +``` + +It automatically opens the browser and you can log in to the provider. + +keycloak-login + +After authentication, kubelogin writes the ID token and refresh token to the kubeconfig. + +``` +% kubelogin +Open http://localhost:8000 for authentication +You got a valid token until 2019-05-18 10:28:51 +0900 JST +Updated ~/.kubeconfig +``` + +Now you can access the cluster. + +``` +% kubectl get pods +NAME READY STATUS RESTARTS AGE +echoserver-86c78fdccd-nzmd5 1/1 Running 0 26d +``` + +Your kubeconfig looks like: + +```yaml +users: +- name: keycloak + user: + auth-provider: + config: + client-id: YOUR_CLIENT_ID + client-secret: YOUR_CLIENT_SECRET + idp-issuer-url: https://issuer.example.com + id-token: ey... # kubelogin will add or update the ID token here + refresh-token: ey... # kubelogin will add or update the refresh token here + name: oidc +``` + +If the ID token is valid, kubelogin does nothing. + +``` +% kubelogin +You already have a valid token until 2019-05-18 10:28:51 +0900 JST +``` + +If the ID token has expired, kubelogin will refresh the token using the refresh token in the kubeconfig. +If the refresh token has expired, kubelogin will proceed the authentication. + + +## Usage + +Kubelogin supports the following options: + +``` +% kubelogin -h +Login to the OpenID Connect provider and update the kubeconfig + +Usage: + kubelogin [flags] + kubelogin [command] + +Examples: + # Login to the provider using the authorization code flow. + kubelogin + + # Login to the provider using the resource owner password credentials flow. + kubelogin --username USERNAME --password PASSWORD + + # Run as a credential plugin. + kubelogin get-token --oidc-issuer-url=https://issuer.example.com + +Available Commands: + get-token Run as a kubectl credential plugin + help Help about any command + version Print the version information + +Flags: + --kubeconfig string Path to the kubeconfig file + --context string The name of the kubeconfig context to use + --user string The name of the kubeconfig user to use. Prior to --context + --certificate-authority string Path to a cert file for the certificate authority + --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure + -v, --v int If set to 1 or greater, it shows debug log + --listen-port ints Port to bind to the local server. If multiple ports are given, it will try the ports in order (default [8000,18000]) + --skip-open-browser If true, it does not open the browser on authentication + --username string If set, perform the resource owner password credentials grant + --password string If set, use the password instead of asking it + -h, --help help for kubelogin +``` + +### Kubeconfig + +You can set path to the kubeconfig file by the option or the environment variable just like kubectl. +It defaults to `~/.kube/config`. + +```sh +# by the option +kubelogin --kubeconfig /path/to/kubeconfig + +# by the environment variable +KUBECONFIG="/path/to/kubeconfig1:/path/to/kubeconfig2" kubelogin +``` + +If you set multiple files, kubelogin will find the file which has the current authentication (i.e. `user` and `auth-provider`) and write a token to it. + +Kubelogin supports the following keys of `auth-provider` in a kubeconfig. +See [kubectl authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#using-kubectl) for more. + +Key | Direction | Value +----|-----------|------ +`idp-issuer-url` | Read (Mandatory) | Issuer URL of the provider. +`client-id` | Read (Mandatory) | Client ID of the provider. +`client-secret` | Read (Mandatory) | Client Secret of the provider. +`idp-certificate-authority` | Read | CA certificate path of the provider. +`idp-certificate-authority-data` | Read | Base64 encoded CA certificate of the provider. +`extra-scopes` | Read | Scopes to request to the provider (comma separated). +`id-token` | Write | ID token got from the provider. +`refresh-token` | Write | Refresh token got from the provider. + +### Extra scopes + +You can set the extra scopes to request to the provider by `extra-scopes` in the kubeconfig. + +```sh +kubectl config set-credentials keycloak --auth-provider-arg extra-scopes=email +``` + +Currently kubectl does not accept multiple scopes, so you need to edit the kubeconfig as like: + +```sh +kubectl config set-credentials keycloak --auth-provider-arg extra-scopes=SCOPES +sed -i '' -e s/SCOPES/email,profile/ $KUBECONFIG +``` + +### CA Certificates + +You can use your self-signed certificates for the provider. + +```sh +kubectl config set-credentials keycloak \ + --auth-provider-arg idp-certificate-authority=$HOME/.kube/keycloak-ca.pem +```