Compare commits

..

64 Commits
seq ... v1.32.4

Author SHA1 Message Date
renovate[bot]
342ace8aec chore(deps): update docker/build-push-action action to v6.16.0 (#1326)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 18:11:41 +00:00
renovate[bot]
259303299e fix(deps): update kubernetes packages to v0.33.0 (#1325)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 00:44:35 +00:00
renovate[bot]
64b42f8f8c fix(deps): update kubernetes packages to v0.32.4 (#1324)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-23 12:16:59 +00:00
renovate[bot]
31f182cc37 chore(deps): update module github.com/golangci/golangci-lint to v1.64.8 (#1319)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 16:11:23 +00:00
renovate[bot]
57873e9338 chore(deps): update module github.com/vektra/mockery/v2 to v2.53.3 (#1320)
* chore(deps): update module github.com/vektra/mockery/v2 to v2.53.3

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/14334521272

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2025-04-08 15:09:55 +00:00
renovate[bot]
531792ba02 fix(deps): update module golang.org/x/term to v0.31.0 (#1318)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-06 03:27:18 +00:00
renovate[bot]
bd66f19bd5 fix(deps): update module golang.org/x/oauth2 to v0.29.0 (#1316)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-05 22:07:27 +00:00
renovate[bot]
951e1c4713 fix(deps): update module golang.org/x/sync to v0.13.0 (#1317)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-05 20:08:24 +00:00
renovate[bot]
aed6620066 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.14.1 (#1315)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-04 00:43:07 +00:00
renovate[bot]
140b612357 fix(deps): update module github.com/chromedp/chromedp to v0.13.6 (#1314)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-03 08:12:27 +00:00
renovate[bot]
efc5ce1571 chore(deps): update dependency go to v1.24.2 (#1312)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-02 02:20:24 +00:00
renovate[bot]
c20af93fd4 fix(deps): update module github.com/chromedp/chromedp to v0.13.5 (#1313)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-02 00:43:44 +00:00
renovate[bot]
6c7e7f7dad fix(deps): update module github.com/golang-jwt/jwt/v5 to v5.2.2 (#1311)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-21 23:08:17 +00:00
renovate[bot]
1af1bb2910 fix(deps): update module github.com/chromedp/chromedp to v0.13.3 (#1310)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-21 05:08:59 +00:00
renovate[bot]
e1863154df fix(deps): update module github.com/chromedp/chromedp to v0.13.2 (#1309)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-20 03:20:40 +00:00
renovate[bot]
c7736355b6 chore(deps): update actions/setup-go action to v5.4.0 (#1308)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-19 05:09:13 +00:00
renovate[bot]
93d83b9365 chore(deps): update docker/login-action action to v3.4.0 (#1306)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-14 12:15:29 +00:00
renovate[bot]
d5f9e3c88e fix(deps): update module github.com/coreos/go-oidc/v3 to v3.13.0 (#1305)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 13:18:53 +00:00
renovate[bot]
4d10746b42 fix(deps): update kubernetes packages to v0.32.3 (#1303)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-12 13:18:26 +00:00
renovate[bot]
b26cd49178 fix(deps): update module github.com/chromedp/chromedp to v0.13.1 (#1302)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 02:14:53 +00:00
renovate[bot]
19aeb78113 chore(deps): update dependency go to v1.24.1 (#1298)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 00:41:54 +00:00
renovate[bot]
b359f0de12 fix(deps): update module golang.org/x/oauth2 to v0.28.0 (#1299)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 22:08:14 +00:00
renovate[bot]
c91e9bee42 fix(deps): update module golang.org/x/term to v0.30.0 (#1301)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 20:09:44 +00:00
renovate[bot]
88fb3c2ea8 fix(deps): update module golang.org/x/sync to v0.12.0 (#1300)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 18:12:12 +00:00
Hidetake Iwata
751469d3b9 Use int128/docker-build-metadata-action (#1297)
* Use int128/docker-build-metadata-action

* Fix conditional check in Docker workflow
2025-03-01 17:08:18 +09:00
renovate[bot]
c29ab9c8ce chore(deps): update docker/setup-qemu-action action to v3.6.0 (#1296)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 16:10:39 +00:00
renovate[bot]
19e4da8f4d chore(deps): update docker/build-push-action action to v6.15.0 (#1290)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-27 02:13:35 +00:00
renovate[bot]
fcb4a27cde chore(deps): update docker/setup-buildx-action action to v3.10.0 (#1292)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-27 00:41:08 +00:00
renovate[bot]
021bc77094 chore(deps): update docker/setup-qemu-action action to v3.5.0 (#1293)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-26 23:08:26 +00:00
renovate[bot]
f9367d6fd1 chore(deps): update docker/metadata-action action to v5.7.0 (#1291)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-26 21:07:51 +00:00
renovate[bot]
516d8bae41 fix(deps): update module golang.org/x/oauth2 to v0.27.0 (#1288)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-24 20:09:54 +00:00
renovate[bot]
22153cc1f4 fix(deps): update module github.com/chromedp/chromedp to v0.13.0 (#1287)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-22 07:07:04 +00:00
renovate[bot]
45dd932876 fix(deps): update module github.com/google/go-cmp to v0.7.0 (#1286)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-22 00:38:46 +00:00
renovate[bot]
6b108ffb9d chore(deps): update docker/build-push-action action to v6.14.0 (#1284)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-19 19:06:43 +00:00
renovate[bot]
cf3063c3bf fix(deps): update module github.com/spf13/cobra to v1.9.1 (#1283)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-17 04:10:52 +00:00
renovate[bot]
c7060d2ca5 fix(deps): update module github.com/spf13/cobra to v1.9.0 (#1282)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-15 20:07:44 +00:00
renovate[bot]
8002eeb191 fix(deps): update kubernetes packages to v0.32.2 (#1281)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-13 20:08:58 +00:00
Hidetake Iwata
b95872b24f Migrate to go tool (#1280)
* Migrate to go tool

* Fix
2025-02-13 21:29:58 +09:00
renovate[bot]
2d5775315f fix(deps): update module github.com/golangci/golangci-lint to v1.64.4 (#1278)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-13 03:12:44 +00:00
renovate[bot]
ba2e5e5fea chore(deps): update dependency go to v1.24.0 (#1275)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-13 02:09:21 +00:00
renovate[bot]
525cdae92d chore(deps): update golang docker tag to v1.24 (#1279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-13 00:40:15 +00:00
renovate[bot]
30b7f47e70 fix(deps): update module github.com/vektra/mockery/v2 to v2.52.2 (#1277)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.52.2

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/13279561144

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2025-02-12 08:11:22 +00:00
renovate[bot]
284cd851ea fix(deps): update module github.com/golangci/golangci-lint to v1.64.2 (#1276)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-12 00:40:02 +00:00
renovate[bot]
4cf5b302fe chore(deps): update docker/setup-buildx-action action to v3.9.0 (#1273)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-06 20:08:46 +00:00
renovate[bot]
63dcbeb6f5 chore(deps): update dependency go to v1.23.6 (#1269)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-06 18:10:51 +00:00
renovate[bot]
ea6b3815bf chore(deps): update docker/setup-qemu-action action to v3.4.0 (#1274)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-06 16:08:34 +00:00
renovate[bot]
a5f746ad6e fix(deps): update module golang.org/x/sync to v0.11.0 (#1271)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-04 21:12:58 +00:00
renovate[bot]
434c69407e fix(deps): update module golang.org/x/term to v0.29.0 (#1272)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-04 20:08:51 +00:00
renovate[bot]
8ec95ed141 fix(deps): update module golang.org/x/oauth2 to v0.26.0 (#1270)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-04 19:06:19 +00:00
renovate[bot]
dee9032023 fix(deps): update module github.com/vektra/mockery/v2 to v2.52.1 (#1268)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.52.1

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/13085455877

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2025-02-01 08:09:43 +00:00
renovate[bot]
cb7a9742ac fix(deps): update module github.com/int128/oauth2cli to v1.15.1 (#1262)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-01 05:07:30 +00:00
renovate[bot]
a3013a12b9 fix(deps): update module github.com/spf13/pflag to v1.0.6 (#1266)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-30 12:22:57 +00:00
Hidetake Iwata
bc7e71f586 Change default token cache storage to disk (#1264)
* Change default token cache storage to disk

* Fix

* Fix

* Clean up both storages
2025-01-30 18:47:07 +09:00
Hidetake Iwata
19d61e70a9 Fix client secret description (#1265) 2025-01-26 16:04:14 +09:00
Hidetake Iwata
3a38753ee7 Refactor setup command and docs (#1253)
* Refactor setup command and docs

* Fix slice flags

* Fix
2025-01-25 16:08:28 +09:00
Johannes Edelstam
56e09ad65e Update instructions for Google OAuth (#1260) 2025-01-25 10:04:12 +09:00
Johannes Edelstam
58a4b1399f Use homebrew main tap (#1259)
Since kubelogin exists in the homebrew main tap use that instead.
2025-01-25 10:02:43 +09:00
James White
6726d851cb Fallback to disk storage if too big for keyring (#1257) 2025-01-25 09:54:28 +09:00
renovate[bot]
21e03dc294 chore(deps): update docker/build-push-action action to v6.13.0 (#1261)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-24 14:07:45 +00:00
renovate[bot]
5f1ed82a85 fix(deps): update module github.com/chromedp/chromedp to v0.12.1 (#1258)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-23 08:11:34 +00:00
renovate[bot]
abb1a564f4 chore(deps): update actions/setup-go action to v5.3.0 (#1256)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 11:06:49 +00:00
renovate[bot]
6d4eee5d1d fix(deps): update module github.com/vektra/mockery/v2 to v2.51.1 (#1254)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.51.1

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/12861944941

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2025-01-20 08:12:01 +00:00
Hidetake Iwata
4c10146639 Refactor integration-test and acceptance-test (#1252)
* Refactor tests

* Fix

* Run plugin

* Fix

* Update acceptance-test.yaml

* Fix
2025-01-20 09:37:10 +09:00
Hidetake Iwata
3121e55498 Update apiVersion to client.authentication.k8s.io/v1 (integration-test) (#1251) 2025-01-19 17:58:55 +09:00
66 changed files with 1611 additions and 1967 deletions

34
.github/workflows/acceptance-test.yaml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: acceptance-test
on:
pull_request:
branches:
- master
paths:
- .github/workflows/acceptance-test.yaml
- acceptance_test/**
push:
branches:
- master
paths:
- .github/workflows/acceptance-test.yaml
- acceptance_test/**
jobs:
test-makefile:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- run: make -C acceptance_test check
- run: make -C acceptance_test
env:
OIDC_ISSUER_URL: https://accounts.google.com
OIDC_CLIENT_ID: REDACTED.apps.googleusercontent.com
YOUR_EMAIL: REDACTED@gmail.com
- run: make -C acceptance_test delete-cluster
- run: make -C acceptance_test clean

View File

@@ -28,15 +28,15 @@ jobs:
contents: read
packages: write
outputs:
image-uri: ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
image-uri: ${{ steps.build-metadata.outputs.image-uri }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1
- uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
id: metadata
with:
images: ghcr.io/${{ github.repository }}
@@ -44,9 +44,9 @@ jobs:
id: cache
with:
image: ghcr.io/${{ github.repository }}/cache
- uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3.3.0
- uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
- uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0
- uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0
id: build
with:
push: ${{ github.event_name == 'push' }}
@@ -58,9 +58,13 @@ jobs:
linux/amd64
linux/arm64
linux/ppc64le
- uses: int128/docker-build-metadata-action@fac3c879c58b212e339c5e959cabb865cbee0c6e # v1.0.0
id: build-metadata
with:
metadata: ${{ steps.build.outputs.metadata }}
test:
if: github.event_name == 'push'
if: needs.build.outputs.image-uri != ''
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10

View File

@@ -30,7 +30,7 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version-file: go.mod
cache-dependency-path: go.sum
@@ -48,7 +48,7 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version-file: go.mod
cache-dependency-path: go.sum
@@ -59,10 +59,10 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version-file: tools/go.mod
cache-dependency-path: tools/go.sum
go-version-file: go.mod
cache-dependency-path: go.sum
- run: make lint
generate:
@@ -70,10 +70,10 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version-file: tools/go.mod
cache-dependency-path: tools/go.sum
go-version-file: go.mod
cache-dependency-path: go.sum
- run: go mod tidy
- run: make generate
- uses: int128/update-generated-files-action@65b9a7ae3ededc5679d78343f58fbebcf1ebd785 # v2.57.0

View File

@@ -58,7 +58,7 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version-file: go.mod
cache-dependency-path: go.sum

View File

@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
- uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version-file: go.mod
cache-dependency-path: go.sum

View File

@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM golang:1.23 AS builder
FROM --platform=$BUILDPLATFORM golang:1.24 AS builder
WORKDIR /builder

View File

@@ -11,12 +11,10 @@ integration-test:
.PHONY: generate
generate:
$(MAKE) -C tools
./tools/bin/wire ./pkg/di
go tool github.com/google/wire/cmd/wire ./pkg/di
rm -fr mocks/
./tools/bin/mockery
go tool github.com/vektra/mockery/v2
.PHONY: lint
lint:
$(MAKE) -C tools
./tools/bin/golangci-lint run
go tool github.com/golangci/golangci-lint/cmd/golangci-lint run

View File

@@ -21,7 +21,7 @@ Install the latest release from [Homebrew](https://brew.sh/), [Krew](https://git
```sh
# Homebrew (macOS and Linux)
brew install int128/kubelogin/kubelogin
brew install kubelogin
# Krew (macOS, Linux, Windows and ARM)
kubectl krew install oidc-login
@@ -83,8 +83,8 @@ If the refresh token has expired, it will perform re-authentication.
### Token cache
If the OS keyring is available, kubelogin stores the token cache to the OS keyring.
Otherwise, kubelogin stores the token cache to the file system.
Kubelogin stores the token cache to the file system by default.
For enhanced security, it is recommended to store it to the keyring.
See the [token cache](docs/usage.md#token-cache) for details.
You can log out by deleting the token cache.
@@ -92,7 +92,7 @@ You can log out by deleting the token cache.
```console
% kubectl oidc-login clean
Deleted the token cache at /home/user/.kube/cache/oidc-login
Deleted the token cache in the keyring
Deleted the token cache from the keyring
```
Kubelogin will ask you to log in via the browser again.

View File

@@ -4,33 +4,38 @@ OUTPUT_DIR := $(CURDIR)/output
KUBECONFIG := $(OUTPUT_DIR)/kubeconfig.yaml
export KUBECONFIG
# create a Kubernetes cluster
.PHONY: cluster
cluster:
# create a cluster
# Create a cluster.
mkdir -p $(OUTPUT_DIR)
sed -e "s|OIDC_ISSUER_URL|$(OIDC_ISSUER_URL)|" -e "s|OIDC_CLIENT_ID|$(OIDC_CLIENT_ID)|" cluster.yaml > $(OUTPUT_DIR)/cluster.yaml
kind create cluster --name $(CLUSTER_NAME) --config $(OUTPUT_DIR)/cluster.yaml
# set up access control
# Set up the access control.
kubectl create clusterrole cluster-readonly --verb=get,watch,list --resource='*.*'
kubectl create clusterrolebinding cluster-readonly --clusterrole=cluster-readonly --user=$(YOUR_EMAIL)
# set up kubectl
# Set up kubectl.
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1beta1 \
--exec-api-version=client.authentication.k8s.io/v1 \
--exec-interactive-mode=Never \
--exec-command=$(CURDIR)/../kubelogin \
--exec-arg=get-token \
--exec-arg=--token-cache-dir=$(OUTPUT_DIR)/token-cache \
--exec-arg=--oidc-issuer-url=$(OIDC_ISSUER_URL) \
--exec-arg=--oidc-client-id=$(OIDC_CLIENT_ID) \
--exec-arg=--oidc-client-secret=$(OIDC_CLIENT_SECRET) \
--exec-arg=--oidc-extra-scope=email
# switch the default user
# Switch the default user.
kubectl config set-context --current --user=oidc
# clean up the resources
# Show the kubeconfig.
kubectl config view
.PHONY: clean
clean:
-rm -r $(OUTPUT_DIR)
.PHONY: delete-cluster
delete-cluster:
kind delete cluster --name $(CLUSTER_NAME)

View File

@@ -1,16 +1,14 @@
# kubelogin/acceptance_test
This is a manual test for verifying Kubernetes OIDC authentication with your OIDC provider.
This is a manual test to verify if the Kubernetes OIDC authentication works with your OIDC provider.
## Purpose
This test checks the following points:
1. You can set up your OIDC provider using [setup guide](../docs/setup.md).
1. You can set up your OIDC provider using the [setup guide](../docs/setup.md).
1. The plugin works with your OIDC provider.
## Getting Started
### Prerequisite
@@ -22,7 +20,7 @@ make -C ..
```
You need to set up your provider.
See [setup guide](../docs/setup.md) for more.
See the [setup guide](../docs/setup.md) for more.
You need to install the following tools:
@@ -44,7 +42,6 @@ For example, you can create a cluster with Google account authentication.
```sh
make OIDC_ISSUER_URL=https://accounts.google.com \
OIDC_CLIENT_ID=REDACTED.apps.googleusercontent.com \
OIDC_CLIENT_SECRET=REDACTED \
YOUR_EMAIL=REDACTED@gmail.com
```

View File

@@ -24,17 +24,18 @@ See the [usage](usage.md) for the details.
You can log in with a Google account.
Open [Google APIs Console](https://console.developers.google.com/apis/credentials) and create an OAuth client with the following setting:
Open [Google APIs Console](https://console.cloud.google.com/apis/credentials) and create an OAuth client with the following setting:
- Application Type: Other
- Application Type: Desktop app
Check the client ID and secret.
Replace the following variables in the later sections.
| Variable | Value |
| ---------------- | -------------------------------- |
| `ISSUER_URL` | `https://accounts.google.com` |
| `YOUR_CLIENT_ID` | `xxx.apps.googleusercontent.com` |
| Variable | Value |
| -------------------- | -------------------------------- |
| `ISSUER_URL` | `https://accounts.google.com` |
| `YOUR_CLIENT_ID` | `xxx.apps.googleusercontent.com` |
| `YOUR_CLIENT_SECRET` | `XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` |
### Keycloak
@@ -67,6 +68,8 @@ Replace the following variables in the later sections.
| `ISSUER_URL` | `https://keycloak.example.com/auth/realms/YOUR_REALM` |
| `YOUR_CLIENT_ID` | `YOUR_CLIENT_ID` |
`YOUR_CLIENT_SECRET` is not required for this configuration.
### Dex with GitHub
You can log in with a GitHub account.
@@ -129,7 +132,7 @@ Replace the following variables in the later sections.
| `ISSUER_URL` | `https://YOUR_ORGANIZATION.okta.com` |
| `YOUR_CLIENT_ID` | random string |
You do not need to set `YOUR_CLIENT_SECRET`.
`YOUR_CLIENT_SECRET` is not required for this configuration.
If you need `groups` claim for access control,
see [jetstack/okta-kubectl-auth](https://github.com/jetstack/okta-kubectl-auth/blob/master/docs/okta-setup.md) and [#250](https://github.com/int128/kubelogin/issues/250).
@@ -154,7 +157,7 @@ Leverage the following variables in the next steps.
`YOUR_CLIENT_SECRET` is not required for this configuration.
## 2. Verify authentication
## 2. Authenticate with the OpenID Connect Provider
Run the following command:
@@ -164,11 +167,12 @@ kubectl oidc-login setup \
--oidc-client-id=YOUR_CLIENT_ID
```
If your provider requires a client secret, add `--oidc-client-secret=YOUR_CLIENT_SECRET`.
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.
For the full options,
```sh
kubectl oidc-login setup --help
@@ -176,14 +180,12 @@ kubectl oidc-login setup --help
## 3. Bind a cluster role
Here bind `cluster-admin` role to you.
You can run the following command to bind `cluster-admin` role to you:
```sh
kubectl create clusterrolebinding oidc-cluster-admin --clusterrole=cluster-admin --user='ISSUER_URL#YOUR_SUBJECT'
```
As well as you can create a custom cluster role and bind it.
## 4. Set up the Kubernetes API server
Add the following flags to kube-apiserver:
@@ -201,6 +203,7 @@ Add `oidc` user to the kubeconfig.
```sh
kubectl config set-credentials oidc \
--exec-interactive-mode=Never \
--exec-api-version=client.authentication.k8s.io/v1 \
--exec-command=kubectl \
--exec-arg=oidc-login \
@@ -209,6 +212,11 @@ kubectl config set-credentials oidc \
--exec-arg=--oidc-client-id=YOUR_CLIENT_ID
```
If your provider requires a client secret, add `--oidc-client-secret=YOUR_CLIENT_SECRET`.
For security, it is recommended to add `--token-cache-storage=keyring` to store the token cache to the keyring instead of the file system.
If you encounter an error, see the [token cache](usage.md#token-cache) for details.
## 6. Verify cluster access
Make sure you can access the Kubernetes cluster.

View File

@@ -14,7 +14,7 @@ Flags:
--oidc-use-access-token Instead of using the id_token, use the access_token to authenticate to Kubernetes
--force-refresh If set, refresh the ID token regardless of its expiration time
--token-cache-dir string Path to a directory of the token cache (default "~/.kube/cache/oidc-login")
--token-cache-storage string Storage for the token cache. One of (auto|keyring|disk) (default "auto")
--token-cache-storage string Storage for the token cache. One of (disk|keyring) (default "disk")
--certificate-authority stringArray Path to a cert file for the certificate authority
--certificate-authority-data stringArray Base64 encoded cert for the certificate authority
--insecure-skip-tls-verify [SECURITY RISK] If set, the server's certificate will not be checked for validity
@@ -52,24 +52,6 @@ Global Flags:
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
Here is the sequence diagram of the credential plugin.
```mermaid
sequenceDiagram
actor User
User ->>+ kubectl: Run
kubectl ->>+ kubelogin: Run the plugin
kubelogin ->>+ Provider: Authentication request
Note over User, Provider: Browser interaction
Provider -->>- kubelogin: Authentication response
kubelogin ->>+ Provider: Token request
Provider -->>- kubelogin: Token response
kubelogin -->>- kubectl: Credential
kubectl ->>+ kube-apiserver: Request with the credential
kube-apiserver -->>- kubectl: Response
kubectl -->>- User: Response
```
## Options
### Authentication timeout
@@ -123,16 +105,21 @@ See also [net/http#ProxyFromEnvironment](https://golang.org/pkg/net/http/#ProxyF
### Token cache
Kubelogin stores the token cache to the OS keyring if available.
It depends on [zalando/go-keyring](https://github.com/zalando/go-keyring) for the keyring storage.
Kubelogin stores the token cache to the file system by default.
If you encounter a problem, try `--token-cache-storage` to set the storage.
You can store the token cache to the OS keyring for enhanced security.
It depends on [zalando/go-keyring](https://github.com/zalando/go-keyring).
```yaml
# Force to use the OS keyring
- --token-cache-storage=keyring
# Force to use the file system
- --token-cache-storage=disk
```
You can delete the token cache by the clean command.
```console
% kubectl oidc-login clean
Deleted the token cache at /home/user/.kube/cache/oidc-login
Deleted the token cache from the keyring
```
### Home directory expansion

235
go.mod
View File

@@ -1,66 +1,247 @@
module github.com/int128/kubelogin
go 1.23.5
go 1.24.2
require (
github.com/chromedp/chromedp v0.11.2
github.com/coreos/go-oidc/v3 v3.12.0
github.com/chromedp/chromedp v0.13.6
github.com/coreos/go-oidc/v3 v3.14.1
github.com/gofrs/flock v0.12.1
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-cmp v0.6.0
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/go-cmp v0.7.0
github.com/google/wire v0.6.0
github.com/int128/oauth2cli v1.14.1
github.com/int128/oauth2cli v1.15.1
github.com/int128/oauth2dev v1.0.1
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
github.com/zalando/go-keyring v0.2.6
golang.org/x/oauth2 v0.25.0
golang.org/x/sync v0.10.0
golang.org/x/term v0.28.0
golang.org/x/oauth2 v0.29.0
golang.org/x/sync v0.13.0
golang.org/x/term v0.31.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.32.1
k8s.io/client-go v0.32.1
k8s.io/apimachinery v0.33.0
k8s.io/client-go v0.33.0
k8s.io/klog/v2 v2.130.1
)
require (
4d63.com/gocheckcompilerdirectives v1.3.0 // indirect
4d63.com/gochecknoglobals v0.2.2 // indirect
al.essio.dev/pkg/shellescape v1.5.1 // indirect
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb // indirect
github.com/4meepo/tagalign v1.4.2 // indirect
github.com/Abirdcfly/dupword v0.1.3 // indirect
github.com/Antonboom/errname v1.0.0 // indirect
github.com/Antonboom/nilnil v1.0.1 // indirect
github.com/Antonboom/testifylint v1.5.2 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/Crocmagnon/fatcontext v0.7.1 // indirect
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
github.com/alexkohler/nakedret/v2 v2.0.5 // indirect
github.com/alexkohler/prealloc v1.0.0 // indirect
github.com/alingse/asasalint v0.0.11 // indirect
github.com/alingse/nilnesserr v0.1.2 // indirect
github.com/ashanbrown/forbidigo v1.6.0 // indirect
github.com/ashanbrown/makezero v1.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bkielbasa/cyclop v1.2.3 // indirect
github.com/blizzy78/varnamelen v0.8.0 // indirect
github.com/bombsimon/wsl/v4 v4.5.0 // indirect
github.com/breml/bidichk v0.3.2 // indirect
github.com/breml/errchkjson v0.4.0 // indirect
github.com/butuzov/ireturn v0.3.1 // indirect
github.com/butuzov/mirror v1.3.0 // indirect
github.com/catenacyber/perfsprint v0.8.2 // indirect
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charithe/durationcheck v0.0.10 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/chigopher/pathlib v0.19.1 // indirect
github.com/chromedp/cdproto v0.0.0-20250403032234-65de8f5d025b // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/ckaznocha/intrange v0.3.0 // indirect
github.com/curioswitch/go-reassign v0.3.0 // indirect
github.com/daixiang0/gci v0.13.5 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
github.com/ettle/strcase v0.2.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/firefart/nonamedreturns v1.0.5 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/ghostiam/protogetter v0.3.9 // indirect
github.com/go-critic/go-critic v0.12.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
github.com/go-toolsmith/astcopy v1.1.0 // indirect
github.com/go-toolsmith/astequal v1.2.0 // indirect
github.com/go-toolsmith/astfmt v1.1.0 // indirect
github.com/go-toolsmith/astp v1.1.0 // indirect
github.com/go-toolsmith/strparse v1.1.0 // indirect
github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
github.com/golangci/go-printf-func-name v0.1.0 // indirect
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect
github.com/golangci/golangci-lint v1.64.8 // indirect
github.com/golangci/misspell v0.6.0 // indirect
github.com/golangci/plugin-module-register v0.1.1 // indirect
github.com/golangci/revgrep v0.8.0 // indirect
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
github.com/google/subcommands v1.2.0 // indirect
github.com/gordonklaus/ineffassign v0.1.0 // indirect
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
github.com/gostaticanalysis/comment v1.5.0 // indirect
github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/int128/listener v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/int128/listener v1.2.0 // indirect
github.com/jgautheron/goconst v1.7.1 // indirect
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/jjti/go-spancheck v0.6.4 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/julz/importas v0.2.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect
github.com/kisielk/errcheck v1.9.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.6 // indirect
github.com/kulti/thelper v0.6.3 // indirect
github.com/kunwardeep/paralleltest v1.0.10 // indirect
github.com/lasiar/canonicalheader v1.1.2 // indirect
github.com/ldez/exptostd v0.4.2 // indirect
github.com/ldez/gomoddirectives v0.6.1 // indirect
github.com/ldez/grignotin v0.9.0 // indirect
github.com/ldez/tagliatelle v0.7.1 // indirect
github.com/ldez/usetesting v0.4.2 // indirect
github.com/leonklingele/grouper v1.1.2 // indirect
github.com/macabu/inamedparam v0.1.3 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/maratori/testableexamples v1.0.0 // indirect
github.com/maratori/testpackage v1.1.1 // indirect
github.com/matoous/godox v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mgechev/revive v1.7.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/moricho/tparallel v0.3.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/nishanths/exhaustive v0.12.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nunnatsa/ginkgolinter v0.19.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/polyfloyd/go-errorlint v1.7.1 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect
github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect
github.com/quasilyte/gogrep v0.5.0 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/raeperd/recvcheck v0.2.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/ryancurrah/gomodguard v1.3.5 // indirect
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
github.com/sashamelentyev/usestdlibvars v1.28.0 // indirect
github.com/securego/gosec/v2 v2.22.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sivchari/tenv v1.12.1 // indirect
github.com/sonatard/noctx v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/sourcegraph/go-diff v0.7.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/viper v1.20.0 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tdakkota/asciicheck v0.4.1 // indirect
github.com/tetafro/godot v1.5.0 // indirect
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 // indirect
github.com/timonwong/loggercheck v0.10.1 // indirect
github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
github.com/ultraware/funlen v0.2.0 // indirect
github.com/ultraware/whitespace v0.2.0 // indirect
github.com/uudashr/gocognit v1.2.0 // indirect
github.com/uudashr/iface v1.3.1 // indirect
github.com/vektra/mockery/v2 v2.53.3 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.7.0 // indirect
github.com/xen0n/gosmopolitan v1.2.2 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.3.0 // indirect
github.com/ykadowak/zerologlint v0.1.5 // indirect
gitlab.com/bosi/decorder v0.4.2 // indirect
go-simpler.org/musttag v0.13.0 // indirect
go-simpler.org/sloglint v0.9.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.10.0 // indirect
golang.org/x/tools v0.31.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
honnef.co/go/tools v0.6.1 // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
mvdan.cc/gofumpt v0.7.0 // indirect
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
tool (
github.com/golangci/golangci-lint/cmd/golangci-lint
github.com/google/wire/cmd/wire
github.com/vektra/mockery/v2
)

991
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,6 @@ func TestClean(t *testing.T) {
"kubelogin",
"clean",
"--token-cache-dir", tokenCacheDir,
"--token-cache-storage", "disk",
}, "HEAD")
if exitCode != 0 {
t.Errorf("exit status wants 0 but %d", exitCode)

View File

@@ -19,7 +19,7 @@ import (
"github.com/int128/kubelogin/pkg/testing/clock"
"github.com/int128/kubelogin/pkg/testing/logger"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1"
)
// Run the integration tests of the credential plugin use-case.
@@ -50,7 +50,6 @@ func TestCredentialPlugin(t *testing.T) {
t.Run(name, func(t *testing.T) {
t.Run("AuthCode", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, tc.keyPair, testconfig.Config{
@@ -77,7 +76,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("ROPC", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, tc.keyPair, testconfig.Config{
@@ -108,7 +106,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("TokenCacheLifecycle", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, tc.keyPair, testconfig.Config{})
@@ -203,7 +200,6 @@ func TestCredentialPlugin(t *testing.T) {
t.Run("PKCE", func(t *testing.T) {
t.Run("Not supported by provider", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, keypair.None, testconfig.Config{
@@ -229,7 +225,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("Enforce", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, keypair.None, testconfig.Config{
@@ -257,7 +252,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("TLSData", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, keypair.Server, testconfig.Config{
@@ -284,7 +278,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("ExtraScopes", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, keypair.None, testconfig.Config{
@@ -314,7 +307,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("OpenURLAfterAuthentication", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, keypair.None, testconfig.Config{
@@ -341,7 +333,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("RedirectURLHostname", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, keypair.None, testconfig.Config{
@@ -368,7 +359,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("RedirectURLHTTPS", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, keypair.None, testconfig.Config{
@@ -401,7 +391,6 @@ func TestCredentialPlugin(t *testing.T) {
})
t.Run("ExtraParams", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
svc := oidcserver.New(t, keypair.None, testconfig.Config{
@@ -446,11 +435,14 @@ type getTokenConfig struct {
func runGetToken(t *testing.T, ctx context.Context, cfg getTokenConfig) {
cmd := di.NewCmdForHeadless(clock.Fake(cfg.now), os.Stdin, cfg.stdout, logger.New(t), cfg.httpDriver)
t.Setenv(
"KUBERNETES_EXEC_INFO",
`{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1","spec":{"interactive":true}}`,
)
exitCode := cmd.Run(ctx, append([]string{
"kubelogin",
"get-token",
"--token-cache-dir", cfg.tokenCacheDir,
"--token-cache-storage", "disk",
"--oidc-issuer-url", cfg.issuerURL,
"--oidc-client-id", "kubernetes",
"--listen-address", "127.0.0.1:0",
@@ -461,22 +453,22 @@ func runGetToken(t *testing.T, ctx context.Context, cfg getTokenConfig) {
}
func assertCredentialPluginStdout(t *testing.T, stdout io.Reader, token string, expiry time.Time) {
var got clientauthenticationv1beta1.ExecCredential
var got clientauthenticationv1.ExecCredential
if err := json.NewDecoder(stdout).Decode(&got); err != nil {
t.Errorf("could not decode json of the credential plugin: %s", err)
return
}
want := clientauthenticationv1beta1.ExecCredential{
want := clientauthenticationv1.ExecCredential{
TypeMeta: metav1.TypeMeta{
APIVersion: "client.authentication.k8s.io/v1beta1",
APIVersion: "client.authentication.k8s.io/v1",
Kind: "ExecCredential",
},
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
Status: &clientauthenticationv1.ExecCredentialStatus{
Token: token,
ExpirationTimestamp: &metav1.Time{Time: expiry},
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("kubeconfig mismatch (-want +got):\n%s", diff)
t.Errorf("stdout mismatch (-want +got):\n%s", diff)
}
}

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package service_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package service_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package cmd_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package reader_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package writer_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package browser_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package clock_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package logger_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package logger_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package logger_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package reader_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package stdio_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package stdio_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package jwt_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package loader_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package writer_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package client_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package client_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package logger_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package loader_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package repository_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package authentication_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package clean_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package credentialplugin_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package setup_mock
@@ -22,48 +22,16 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
return &MockInterface_Expecter{mock: &_m.Mock}
}
// DoStage1 provides a mock function with no fields
func (_m *MockInterface) DoStage1() {
_m.Called()
}
// MockInterface_DoStage1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DoStage1'
type MockInterface_DoStage1_Call struct {
*mock.Call
}
// DoStage1 is a helper method to define mock.On call
func (_e *MockInterface_Expecter) DoStage1() *MockInterface_DoStage1_Call {
return &MockInterface_DoStage1_Call{Call: _e.mock.On("DoStage1")}
}
func (_c *MockInterface_DoStage1_Call) Run(run func()) *MockInterface_DoStage1_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockInterface_DoStage1_Call) Return() *MockInterface_DoStage1_Call {
_c.Call.Return()
return _c
}
func (_c *MockInterface_DoStage1_Call) RunAndReturn(run func()) *MockInterface_DoStage1_Call {
_c.Run(run)
return _c
}
// DoStage2 provides a mock function with given fields: ctx, in
func (_m *MockInterface) DoStage2(ctx context.Context, in setup.Stage2Input) error {
// Do provides a mock function with given fields: ctx, in
func (_m *MockInterface) Do(ctx context.Context, in setup.Input) error {
ret := _m.Called(ctx, in)
if len(ret) == 0 {
panic("no return value specified for DoStage2")
panic("no return value specified for Do")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, setup.Stage2Input) error); ok {
if rf, ok := ret.Get(0).(func(context.Context, setup.Input) error); ok {
r0 = rf(ctx, in)
} else {
r0 = ret.Error(0)
@@ -72,31 +40,31 @@ func (_m *MockInterface) DoStage2(ctx context.Context, in setup.Stage2Input) err
return r0
}
// MockInterface_DoStage2_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DoStage2'
type MockInterface_DoStage2_Call struct {
// MockInterface_Do_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Do'
type MockInterface_Do_Call struct {
*mock.Call
}
// DoStage2 is a helper method to define mock.On call
// Do is a helper method to define mock.On call
// - ctx context.Context
// - in setup.Stage2Input
func (_e *MockInterface_Expecter) DoStage2(ctx interface{}, in interface{}) *MockInterface_DoStage2_Call {
return &MockInterface_DoStage2_Call{Call: _e.mock.On("DoStage2", ctx, in)}
// - in setup.Input
func (_e *MockInterface_Expecter) Do(ctx interface{}, in interface{}) *MockInterface_Do_Call {
return &MockInterface_Do_Call{Call: _e.mock.On("Do", ctx, in)}
}
func (_c *MockInterface_DoStage2_Call) Run(run func(ctx context.Context, in setup.Stage2Input)) *MockInterface_DoStage2_Call {
func (_c *MockInterface_Do_Call) Run(run func(ctx context.Context, in setup.Input)) *MockInterface_Do_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(setup.Stage2Input))
run(args[0].(context.Context), args[1].(setup.Input))
})
return _c
}
func (_c *MockInterface_DoStage2_Call) Return(_a0 error) *MockInterface_DoStage2_Call {
func (_c *MockInterface_Do_Call) Return(_a0 error) *MockInterface_Do_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockInterface_DoStage2_Call) RunAndReturn(run func(context.Context, setup.Stage2Input) error) *MockInterface_DoStage2_Call {
func (_c *MockInterface_Do_Call) RunAndReturn(run func(context.Context, setup.Input) error) *MockInterface_Do_Call {
_c.Call.Return(run)
return _c
}

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package standalone_mock

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.51.0. DO NOT EDIT.
// Code generated by mockery v2.53.3. DO NOT EDIT.
package io_mock

View File

@@ -9,15 +9,11 @@ import (
)
type cleanOptions struct {
tokenCacheOptions tokenCacheOptions
TokenCacheDir string
}
func (o *cleanOptions) addFlags(f *pflag.FlagSet) {
o.tokenCacheOptions.addFlags(f)
}
func (o *cleanOptions) expandHomedir() {
o.tokenCacheOptions.expandHomedir()
f.StringVar(&o.TokenCacheDir, "token-cache-dir", getDefaultTokenCacheDir(), "Path to a directory of the token cache")
}
type Clean struct {
@@ -31,18 +27,13 @@ func (cmd *Clean) New() *cobra.Command {
Short: "Delete the token cache",
Long: `Delete the token cache.
This deletes both the OS keyring and the directory by default.
If you encounter an error of keyring, try --token-cache-storage=disk.
This deletes the token cache directory from both the file system and the keyring.
`,
Args: cobra.NoArgs,
RunE: func(c *cobra.Command, _ []string) error {
o.expandHomedir()
tokenCacheConfig, err := o.tokenCacheOptions.tokenCacheConfig()
if err != nil {
return fmt.Errorf("clean: %w", err)
}
o.TokenCacheDir = expandHomedir(o.TokenCacheDir)
in := clean.Input{
TokenCacheConfig: tokenCacheConfig,
TokenCacheDir: o.TokenCacheDir,
}
if err := cmd.Clean.Do(c.Context(), in); err != nil {
return fmt.Errorf("clean: %w", err)

View File

@@ -8,6 +8,7 @@ import (
"time"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/credentialplugin_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/setup_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/standalone_mock"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/testing/logger"
@@ -16,6 +17,7 @@ import (
"github.com/int128/kubelogin/pkg/usecases/authentication"
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
"github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/int128/kubelogin/pkg/usecases/setup"
"github.com/int128/kubelogin/pkg/usecases/standalone"
)
@@ -23,6 +25,14 @@ func TestCmd_Run(t *testing.T) {
const executable = "kubelogin"
const version = "HEAD"
defaultGrantOptionSet := authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
}
t.Run("root", func(t *testing.T) {
tests := map[string]struct {
args []string
@@ -31,13 +41,7 @@ func TestCmd_Run(t *testing.T) {
"Defaults": {
args: []string{executable},
in: standalone.Input{
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
GrantOptionSet: defaultGrantOptionSet,
},
},
"FullOptions": {
@@ -51,13 +55,7 @@ func TestCmd_Run(t *testing.T) {
KubeconfigFilename: "/path/to/kubeconfig",
KubeconfigContext: "hello.k8s.local",
KubeconfigUser: "google",
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
GrantOptionSet: defaultGrantOptionSet,
},
},
}
@@ -120,15 +118,8 @@ func TestCmd_Run(t *testing.T) {
},
TokenCacheConfig: tokencache.Config{
Directory: filepath.Join(userHomeDir, ".kube/cache/oidc-login"),
Storage: tokencache.StorageAuto,
},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
GrantOptionSet: defaultGrantOptionSet,
},
},
"FullOptions": {
@@ -139,7 +130,7 @@ func TestCmd_Run(t *testing.T) {
"--oidc-client-secret", "YOUR_CLIENT_SECRET",
"--oidc-extra-scope", "email",
"--oidc-extra-scope", "profile",
"--token-cache-storage", "disk",
"--token-cache-storage", "keyring",
"-v1",
},
in: credentialplugin.Input{
@@ -151,15 +142,9 @@ func TestCmd_Run(t *testing.T) {
},
TokenCacheConfig: tokencache.Config{
Directory: filepath.Join(userHomeDir, ".kube/cache/oidc-login"),
Storage: tokencache.StorageDisk,
},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
Storage: tokencache.StorageKeyring,
},
GrantOptionSet: defaultGrantOptionSet,
},
},
"AccessToken": {
@@ -177,15 +162,8 @@ func TestCmd_Run(t *testing.T) {
},
TokenCacheConfig: tokencache.Config{
Directory: filepath.Join(userHomeDir, ".kube/cache/oidc-login"),
Storage: tokencache.StorageAuto,
},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
GrantOptionSet: defaultGrantOptionSet,
},
},
"HomedirExpansion": {
@@ -205,7 +183,6 @@ func TestCmd_Run(t *testing.T) {
},
TokenCacheConfig: tokencache.Config{
Directory: filepath.Join(userHomeDir, ".kube/oidc-cache"),
Storage: tokencache.StorageAuto,
},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
@@ -282,4 +259,54 @@ func TestCmd_Run(t *testing.T) {
}
})
})
t.Run("setup", func(t *testing.T) {
t.Run("NoOption", func(t *testing.T) {
ctx := context.TODO()
cmd := Cmd{
Logger: logger.New(t),
Root: &Root{
Logger: logger.New(t),
},
}
exitCode := cmd.Run(ctx, []string{executable, "setup"}, version)
if exitCode != 0 {
t.Errorf("exitCode wants 0 but %d", exitCode)
}
})
t.Run("WithOptions", func(t *testing.T) {
ctx := context.TODO()
setupMock := setup_mock.NewMockInterface(t)
setupMock.EXPECT().Do(ctx, setup.Input{
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT",
ExtraScopes: []string{"email", "profile"},
GrantOptionSet: defaultGrantOptionSet,
ChangedFlags: []string{
"--oidc-issuer-url=https://issuer.example.com",
"--oidc-client-id=YOUR_CLIENT",
"--oidc-extra-scope=email",
"--oidc-extra-scope=profile",
},
}).Return(nil)
cmd := Cmd{
Logger: logger.New(t),
Root: &Root{
Logger: logger.New(t),
},
Setup: &Setup{
Setup: setupMock,
},
}
exitCode := cmd.Run(ctx, []string{executable, "setup",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT",
"--oidc-extra-scope", "email,profile",
}, version)
if exitCode != 0 {
t.Errorf("exitCode wants 0 but %d", exitCode)
}
})
})
}

View File

@@ -3,6 +3,8 @@ package cmd
import (
"fmt"
_ "embed"
"github.com/int128/kubelogin/pkg/usecases/setup"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -35,13 +37,31 @@ type Setup struct {
Setup setup.Interface
}
//go:embed setup.md
var setupLongDescription string
func (cmd *Setup) New() *cobra.Command {
var o setupOptions
c := &cobra.Command{
Use: "setup",
Short: "Show the setup instruction",
Long: setupLongDescription,
Args: cobra.NoArgs,
RunE: func(c *cobra.Command, _ []string) error {
var changedFlags []string
c.Flags().VisitAll(func(f *pflag.Flag) {
if !f.Changed {
return
}
if sliceValue, ok := f.Value.(pflag.SliceValue); ok {
for _, v := range sliceValue.GetSlice() {
changedFlags = append(changedFlags, fmt.Sprintf("--%s=%s", f.Name, v))
}
return
}
changedFlags = append(changedFlags, fmt.Sprintf("--%s=%s", f.Name, f.Value))
})
grantOptionSet, err := o.authenticationOptions.grantOptionSet()
if err != nil {
return fmt.Errorf("setup: %w", err)
@@ -50,7 +70,7 @@ func (cmd *Setup) New() *cobra.Command {
if err != nil {
return fmt.Errorf("setup: %w", err)
}
in := setup.Stage2Input{
in := setup.Input{
IssuerURL: o.IssuerURL,
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,
@@ -59,18 +79,12 @@ func (cmd *Setup) New() *cobra.Command {
PKCEMethod: pkceMethod,
GrantOptionSet: grantOptionSet,
TLSClientConfig: o.tlsOptions.tlsClientConfig(),
}
if c.Flags().Lookup("listen-address").Changed {
in.ListenAddressArgs = o.authenticationOptions.ListenAddress
}
if c.Flags().Lookup("oidc-pkce-method").Changed {
in.PKCEMethodArg = o.pkceOptions.PKCEMethod
ChangedFlags: changedFlags,
}
if in.IssuerURL == "" || in.ClientID == "" {
cmd.Setup.DoStage1()
return nil
return c.Help()
}
if err := cmd.Setup.DoStage2(c.Context(), in); err != nil {
if err := cmd.Setup.Do(c.Context(), in); err != nil {
return fmt.Errorf("setup: %w", err)
}
return nil

12
pkg/cmd/setup.md Normal file
View File

@@ -0,0 +1,12 @@
This setup shows the instruction of Kubernetes OpenID Connect authentication.
You need to set up the OpenID Connect Provider.
Run the following command to authenticate with the OpenID Connect Provider:
```
kubectl oidc-login setup \
--oidc-issuer-url=ISSUER_URL \
--oidc-client-id=YOUR_CLIENT_ID
```
See https://github.com/int128/kubelogin for the details.

View File

@@ -18,7 +18,7 @@ func getDefaultTokenCacheDir() string {
return filepath.Join("~", ".kube", "cache", "oidc-login")
}
var allTokenCacheStorage = strings.Join([]string{"auto", "keyring", "disk"}, "|")
var allTokenCacheStorage = strings.Join([]string{"disk", "keyring"}, "|")
type tokenCacheOptions struct {
TokenCacheDir string
@@ -27,7 +27,7 @@ type tokenCacheOptions struct {
func (o *tokenCacheOptions) addFlags(f *pflag.FlagSet) {
f.StringVar(&o.TokenCacheDir, "token-cache-dir", getDefaultTokenCacheDir(), "Path to a directory of the token cache")
f.StringVar(&o.TokenCacheStorage, "token-cache-storage", "auto", fmt.Sprintf("Storage for the token cache. One of (%s)", allTokenCacheStorage))
f.StringVar(&o.TokenCacheStorage, "token-cache-storage", "disk", fmt.Sprintf("Storage for the token cache. One of (%s)", allTokenCacheStorage))
}
func (o *tokenCacheOptions) expandHomedir() {
@@ -39,12 +39,10 @@ func (o *tokenCacheOptions) tokenCacheConfig() (tokencache.Config, error) {
Directory: o.TokenCacheDir,
}
switch o.TokenCacheStorage {
case "auto":
config.Storage = tokencache.StorageAuto
case "keyring":
config.Storage = tokencache.StorageKeyring
case "disk":
config.Storage = tokencache.StorageDisk
case "keyring":
config.Storage = tokencache.StorageKeyring
default:
return tokencache.Config{}, fmt.Errorf("token-cache-storage must be one of (%s)", allTokenCacheStorage)
}

View File

@@ -97,9 +97,7 @@ func NewCmdForHeadless(clockInterface clock.Interface, stdin stdio.Stdin, stdout
Standalone: standaloneStandalone,
Logger: loggerInterface,
}
repositoryRepository := &repository.Repository{
Logger: loggerInterface,
}
repositoryRepository := &repository.Repository{}
reader3 := &reader2.Reader{}
writer3 := &writer2.Writer{
Stdout: stdout,

View File

@@ -5,7 +5,6 @@ import (
"encoding/gob"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"os"
@@ -13,7 +12,6 @@ import (
"github.com/gofrs/flock"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/tokencache"
"github.com/zalando/go-keyring"
@@ -39,9 +37,7 @@ type entity struct {
// Repository provides access to the token cache on the local filesystem.
// Filename of a token cache is sha256 digest of the issuer, zero-character and client ID.
type Repository struct {
Logger logger.Interface
}
type Repository struct{}
// keyringService is used to namespace the keyring access.
// Some implementations may also display this string when prompting the user
@@ -57,16 +53,6 @@ func (r *Repository) FindByKey(config tokencache.Config, key tokencache.Key) (*o
return nil, fmt.Errorf("could not compute the key: %w", err)
}
switch config.Storage {
case tokencache.StorageAuto:
t, err := readFromKeyring(checksum)
if errors.Is(err, keyring.ErrUnsupportedPlatform) ||
errors.Is(err, keyring.ErrNotFound) {
return readFromFile(config, checksum)
}
if err != nil {
return nil, err
}
return t, nil
case tokencache.StorageDisk:
return readFromFile(config, checksum)
case tokencache.StorageKeyring:
@@ -120,14 +106,6 @@ func (r *Repository) Save(config tokencache.Config, key tokencache.Key, tokenSet
return fmt.Errorf("could not compute the key: %w", err)
}
switch config.Storage {
case tokencache.StorageAuto:
if err := writeToKeyring(checksum, tokenSet); err != nil {
if errors.Is(err, keyring.ErrUnsupportedPlatform) {
return writeToFile(config, checksum, tokenSet)
}
return err
}
return nil
case tokencache.StorageDisk:
return writeToFile(config, checksum, tokenSet)
case tokencache.StorageKeyring:
@@ -185,36 +163,20 @@ func (r *Repository) Lock(config tokencache.Config, key tokencache.Key) (io.Clos
}
func (r *Repository) DeleteAll(config tokencache.Config) error {
return errors.Join(
func() error {
if err := os.RemoveAll(config.Directory); err != nil {
return fmt.Errorf("remove the directory %s: %w", config.Directory, err)
}
r.Logger.Printf("Deleted the token cache at %s", config.Directory)
return nil
}(),
func() error {
switch config.Storage {
case tokencache.StorageAuto:
if err := keyring.DeleteAll(keyringService); err != nil {
if errors.Is(err, keyring.ErrUnsupportedPlatform) {
return nil
}
return fmt.Errorf("keyring delete: %w", err)
}
r.Logger.Printf("Deleted the token cache in the keyring")
return nil
case tokencache.StorageKeyring:
if err := keyring.DeleteAll(keyringService); err != nil {
return fmt.Errorf("keyring delete: %w", err)
}
r.Logger.Printf("Deleted the token cache in the keyring")
return nil
default:
return nil
}
}(),
)
switch config.Storage {
case tokencache.StorageDisk:
if err := os.RemoveAll(config.Directory); err != nil {
return fmt.Errorf("remove the directory %s: %w", config.Directory, err)
}
return nil
case tokencache.StorageKeyring:
if err := keyring.DeleteAll(keyringService); err != nil {
return fmt.Errorf("keyring delete: %w", err)
}
return nil
default:
return fmt.Errorf("unknown storage mode: %v", config.Storage)
}
}
func encodeKey(tokenSet oidc.TokenSet) ([]byte, error) {

View File

@@ -25,10 +25,8 @@ type Config struct {
type Storage byte
const (
// StorageAuto will prefer keyring when available, and fallback to disk when not.
StorageAuto Storage = iota
// StorageDisk will only store cached keys on disk.
StorageDisk
StorageDisk Storage = iota
// StorageDisk will only store cached keys in the OS keyring.
StorageKeyring
)

View File

@@ -21,7 +21,7 @@ type Interface interface {
// Input represents an input of the Clean use-case.
type Input struct {
TokenCacheConfig tokencache.Config
TokenCacheDir string
}
type Clean struct {
@@ -31,8 +31,17 @@ type Clean struct {
func (u *Clean) Do(ctx context.Context, in Input) error {
u.Logger.V(1).Infof("Deleting the token cache")
if err := u.TokenCacheRepository.DeleteAll(in.TokenCacheConfig); err != nil {
return fmt.Errorf("delete the token cache: %w", err)
if err := u.TokenCacheRepository.DeleteAll(tokencache.Config{Directory: in.TokenCacheDir, Storage: tokencache.StorageDisk}); err != nil {
return fmt.Errorf("delete the token cache from %s: %w", in.TokenCacheDir, err)
}
u.Logger.Printf("Deleted the token cache from %s", in.TokenCacheDir)
if err := u.TokenCacheRepository.DeleteAll(tokencache.Config{Directory: in.TokenCacheDir, Storage: tokencache.StorageKeyring}); err != nil {
// Do not return an error because the keyring may not be available.
u.Logger.Printf("Could not delete the token cache from the keyring: %s", err)
} else {
u.Logger.Printf("Deleted the token cache from the keyring")
}
return nil
}

View File

@@ -3,9 +3,17 @@ package setup
import (
"context"
"fmt"
"strconv"
"strings"
"text/template"
_ "embed"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/int128/kubelogin/pkg/usecases/authentication"
)
@@ -15,11 +23,62 @@ var Set = wire.NewSet(
)
type Interface interface {
DoStage1()
DoStage2(ctx context.Context, in Stage2Input) error
Do(ctx context.Context, in Input) error
}
type Setup struct {
Authentication authentication.Interface
Logger logger.Interface
}
//go:embed setup.md
var setupMarkdown string
var setupTemplate = template.Must(template.New("setup.md").Funcs(template.FuncMap{
"quote": strconv.Quote,
}).Parse(setupMarkdown))
type Input struct {
IssuerURL string
ClientID string
ClientSecret string
ExtraScopes []string
UseAccessToken bool
PKCEMethod oidc.PKCEMethod
GrantOptionSet authentication.GrantOptionSet
TLSClientConfig tlsclientconfig.Config
ChangedFlags []string
}
func (u Setup) Do(ctx context.Context, in Input) error {
u.Logger.Printf("Authentication in progress...")
out, err := u.Authentication.Do(ctx, authentication.Input{
Provider: oidc.Provider{
IssuerURL: in.IssuerURL,
ClientID: in.ClientID,
ClientSecret: in.ClientSecret,
ExtraScopes: in.ExtraScopes,
PKCEMethod: in.PKCEMethod,
UseAccessToken: in.UseAccessToken,
},
GrantOptionSet: in.GrantOptionSet,
TLSClientConfig: in.TLSClientConfig,
})
if err != nil {
return fmt.Errorf("authentication error: %w", err)
}
idTokenClaims, err := out.TokenSet.DecodeWithoutVerify()
if err != nil {
return fmt.Errorf("you got an invalid token: %w", err)
}
var b strings.Builder
if err := setupTemplate.Execute(&b, map[string]any{
"IDTokenPrettyJSON": idTokenClaims.Pretty,
"Flags": in.ChangedFlags,
}); err != nil {
return fmt.Errorf("render the template: %w", err)
}
u.Logger.Printf(b.String())
return nil
}

View File

@@ -0,0 +1,24 @@
## Authenticated with the OpenID Connect Provider
You got the token with the following claims:
```
{{ .IDTokenPrettyJSON }}
```
## Set up the kubeconfig
You can run the following command to set up the kubeconfig:
```
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1 \
--exec-interactive-mode=Never \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \
{{- range $index, $flag := .Flags }}
{{- if $index}} \{{end}}
--exec-arg={{ $flag | quote }}
{{- end }}
```

View File

@@ -0,0 +1,66 @@
package setup
import (
"context"
"testing"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/authentication_mock"
"github.com/int128/kubelogin/pkg/oidc"
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
"github.com/int128/kubelogin/pkg/testing/logger"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/int128/kubelogin/pkg/usecases/authentication"
)
func TestSetup_Do(t *testing.T) {
issuedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
claims.Issuer = "https://issuer.example.com"
claims.Subject = "YOUR_SUBJECT"
claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(1 * time.Hour))
})
dummyTLSClientConfig := tlsclientconfig.Config{
CACertFilename: []string{"/path/to/cert"},
}
var grantOptionSet authentication.GrantOptionSet
ctx := context.Background()
in := Input{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"email"},
GrantOptionSet: grantOptionSet,
TLSClientConfig: dummyTLSClientConfig,
ChangedFlags: []string{
"--oidc-issuer-url=https://accounts.google.com",
"--oidc-client-id=YOUR_CLIENT_ID",
},
}
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"email"},
},
GrantOptionSet: grantOptionSet,
TLSClientConfig: dummyTLSClientConfig,
}).
Return(&authentication.Output{
TokenSet: oidc.TokenSet{
IDToken: issuedIDToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
},
}, nil)
u := Setup{
Authentication: mockAuthentication,
Logger: logger.New(t),
}
if err := u.Do(ctx, in); err != nil {
t.Errorf("Do returned error: %+v", err)
}
}

View File

@@ -1,28 +0,0 @@
package setup
const stage1 = `This setup shows the instruction of Kubernetes OpenID Connect authentication.
See also https://github.com/int128/kubelogin.
## 1. Set up the OpenID Connect Provider
Open the OpenID Connect Provider and create a client.
For example, Google Identity Platform:
Open https://console.developers.google.com/apis/credentials and create an OAuth client of "Other" type.
ISSUER is https://accounts.google.com
## 2. Verify authentication
Run the following command to proceed.
kubectl oidc-login setup \
--oidc-issuer-url=ISSUER \
--oidc-client-id=YOUR_CLIENT_ID \
--oidc-client-secret=YOUR_CLIENT_SECRET
You can set your CA certificate. See also the options by --help.
`
func (u *Setup) DoStage1() {
u.Logger.Printf(stage1)
}

View File

@@ -1,178 +0,0 @@
package setup
import (
"context"
"fmt"
"path/filepath"
"strings"
"text/template"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/int128/kubelogin/pkg/usecases/authentication"
)
var stage2Tpl = template.Must(template.New("").Parse(`
## 2. Verify authentication
You got a token with the following claims:
{{ .IDTokenPrettyJSON }}
## 3. Bind a cluster role
Run the following command:
kubectl create clusterrolebinding oidc-cluster-admin --clusterrole=cluster-admin --user='{{ .IssuerURL }}#{{ .Subject }}'
## 4. Set up the Kubernetes API server
Add the following options to the kube-apiserver:
--oidc-issuer-url={{ .IssuerURL }}
--oidc-client-id={{ .ClientID }}
## 5. Set up the kubeconfig
Run the following command:
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1 \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \
{{- range $index, $arg := .Args }}
{{- if $index}} \{{end}}
--exec-arg={{ $arg }}
{{- end }}
## 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 {
IDTokenPrettyJSON string
IssuerURL string
ClientID string
Args []string
Subject string
}
// Stage2Input represents an input DTO of the stage2.
type Stage2Input struct {
IssuerURL string
ClientID string
ClientSecret string
ExtraScopes []string // optional
UseAccessToken bool // optional
ListenAddressArgs []string // non-nil if set by the command arg
PKCEMethod oidc.PKCEMethod
PKCEMethodArg string
GrantOptionSet authentication.GrantOptionSet
TLSClientConfig tlsclientconfig.Config
}
func (u *Setup) DoStage2(ctx context.Context, in Stage2Input) error {
u.Logger.Printf("authentication in progress...")
out, err := u.Authentication.Do(ctx, authentication.Input{
Provider: oidc.Provider{
IssuerURL: in.IssuerURL,
ClientID: in.ClientID,
ClientSecret: in.ClientSecret,
ExtraScopes: in.ExtraScopes,
PKCEMethod: in.PKCEMethod,
UseAccessToken: in.UseAccessToken,
},
GrantOptionSet: in.GrantOptionSet,
TLSClientConfig: in.TLSClientConfig,
})
if err != nil {
return fmt.Errorf("authentication error: %w", err)
}
idTokenClaims, err := out.TokenSet.DecodeWithoutVerify()
if err != nil {
return fmt.Errorf("you got an invalid token: %w", err)
}
v := stage2Vars{
IDTokenPrettyJSON: idTokenClaims.Pretty,
IssuerURL: in.IssuerURL,
ClientID: in.ClientID,
Args: makeCredentialPluginArgs(in),
Subject: idTokenClaims.Subject,
}
var b strings.Builder
if err := stage2Tpl.Execute(&b, &v); err != nil {
return fmt.Errorf("could not render the template: %w", err)
}
u.Logger.Printf(b.String())
return nil
}
func makeCredentialPluginArgs(in Stage2Input) []string {
var args []string
args = append(args, "--oidc-issuer-url="+in.IssuerURL)
args = append(args, "--oidc-client-id="+in.ClientID)
if in.ClientSecret != "" {
args = append(args, "--oidc-client-secret="+in.ClientSecret)
}
for _, extraScope := range in.ExtraScopes {
args = append(args, "--oidc-extra-scope="+extraScope)
}
if in.PKCEMethodArg != "" {
args = append(args, "--oidc-pkce-method="+in.PKCEMethodArg)
}
if in.UseAccessToken {
args = append(args, "--oidc-use-access-token")
}
for _, f := range in.TLSClientConfig.CACertFilename {
args = append(args, "--certificate-authority="+f)
}
for _, d := range in.TLSClientConfig.CACertData {
args = append(args, "--certificate-authority-data="+d)
}
if in.TLSClientConfig.SkipTLSVerify {
args = append(args, "--insecure-skip-tls-verify")
}
if in.GrantOptionSet.AuthCodeBrowserOption != nil {
if in.GrantOptionSet.AuthCodeBrowserOption.SkipOpenBrowser {
args = append(args, "--skip-open-browser")
}
if in.GrantOptionSet.AuthCodeBrowserOption.BrowserCommand != "" {
args = append(args, "--browser-command="+in.GrantOptionSet.AuthCodeBrowserOption.BrowserCommand)
}
if in.GrantOptionSet.AuthCodeBrowserOption.LocalServerCertFile != "" {
// Resolve the absolute path for the cert files so the user doesn't have to know
// to use one when running setup.
certpath, err := filepath.Abs(in.GrantOptionSet.AuthCodeBrowserOption.LocalServerCertFile)
if err != nil {
panic(err)
}
keypath, err := filepath.Abs(in.GrantOptionSet.AuthCodeBrowserOption.LocalServerKeyFile)
if err != nil {
panic(err)
}
args = append(args, "--local-server-cert="+certpath)
args = append(args, "--local-server-key="+keypath)
}
}
for _, l := range in.ListenAddressArgs {
args = append(args, "--listen-address="+l)
}
if in.GrantOptionSet.ROPCOption != nil {
if in.GrantOptionSet.ROPCOption.Username != "" {
args = append(args, "--username="+in.GrantOptionSet.ROPCOption.Username)
}
}
return args
}

View File

@@ -1,111 +0,0 @@
package setup
import (
"context"
"testing"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/authentication_mock"
"github.com/int128/kubelogin/pkg/oidc"
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
"github.com/int128/kubelogin/pkg/testing/logger"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/int128/kubelogin/pkg/usecases/authentication"
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
"github.com/int128/kubelogin/pkg/usecases/authentication/ropc"
"github.com/stretchr/testify/assert"
)
func TestSetup_DoStage2(t *testing.T) {
issuedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
claims.Issuer = "https://issuer.example.com"
claims.Subject = "YOUR_SUBJECT"
claims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(1 * time.Hour))
})
dummyTLSClientConfig := tlsclientconfig.Config{
CACertFilename: []string{"/path/to/cert"},
}
var grantOptionSet authentication.GrantOptionSet
ctx := context.Background()
in := Stage2Input{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"email"},
GrantOptionSet: grantOptionSet,
TLSClientConfig: dummyTLSClientConfig,
}
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"email"},
},
GrantOptionSet: grantOptionSet,
TLSClientConfig: dummyTLSClientConfig,
}).
Return(&authentication.Output{
TokenSet: oidc.TokenSet{
IDToken: issuedIDToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
},
}, nil)
u := Setup{
Authentication: mockAuthentication,
Logger: logger.New(t),
}
if err := u.DoStage2(ctx, in); err != nil {
t.Errorf("DoStage2 returned error: %+v", err)
}
}
func Test_makeCredentialPluginArgs(t *testing.T) {
in := Stage2Input{
IssuerURL: "https://oidc.example.com",
ClientID: "test_kid",
ClientSecret: "test_ksecret",
ExtraScopes: []string{"groups"},
PKCEMethodArg: "S256",
ListenAddressArgs: []string{"127.0.0.1:8080", "127.0.0.1:8888"},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
SkipOpenBrowser: true,
BrowserCommand: "firefox",
LocalServerCertFile: "/path/to/cert.crt",
LocalServerKeyFile: "/path/to/cert.key",
},
ROPCOption: &ropc.Option{
Username: "user1",
},
},
TLSClientConfig: tlsclientconfig.Config{
CACertFilename: []string{"/path/to/ca.crt"},
CACertData: []string{"base64encoded1"},
SkipTLSVerify: true,
},
}
expet := []string{
"--oidc-issuer-url=https://oidc.example.com",
"--oidc-client-id=test_kid",
"--oidc-client-secret=test_ksecret",
"--oidc-extra-scope=groups",
"--oidc-pkce-method=S256",
"--certificate-authority=/path/to/ca.crt",
"--certificate-authority-data=base64encoded1",
"--insecure-skip-tls-verify",
"--skip-open-browser",
"--browser-command=firefox",
"--local-server-cert=/path/to/cert.crt",
"--local-server-key=/path/to/cert.key",
"--listen-address=127.0.0.1:8080",
"--listen-address=127.0.0.1:8888",
"--username=user1",
}
got := makeCredentialPluginArgs(in)
assert.Equal(t, expet, got)
}

View File

@@ -2,12 +2,11 @@
This is an automated test for verifying behavior of the plugin with a real Kubernetes cluster and OIDC provider.
## Purpose
This test checks the following points:
1. User can set up Kubernetes OIDC authentication using [setup guide](../docs/setup.md).
1. User can set up Kubernetes OIDC authentication using the [setup guide](../docs/setup.md).
1. User can log in to an OIDC provider on a browser.
1. User can access the cluster using a token returned from the plugin.
@@ -18,7 +17,6 @@ It depends on the following components:
- Browser (Chrome)
- kubectl command
## How it works
Let's take a look at the diagram.
@@ -45,7 +43,6 @@ It performs the test by the following steps:
1. kube-apiserver verifies the token by Dex.
1. Check if kubectl exited with code 0.
## Run locally
You need to set up the following components:
@@ -80,7 +77,6 @@ make terminate
make clean
```
## Technical consideration
### Network and DNS

View File

@@ -8,13 +8,16 @@ export KUBECONFIG
cluster:
cp $(CERT_DIR)/ca.crt /tmp/kubelogin-system-test-dex-ca.crt
kind create cluster --name $(CLUSTER_NAME) --config cluster.yaml
# add the Dex container IP to /etc/hosts
# Add the Dex container IP to /etc/hosts.
docker inspect -f '{{.NetworkSettings.Networks.kind.IPAddress}}' dex-server | sed -e 's,$$, dex-server,' | \
docker exec -i $(CLUSTER_NAME)-control-plane tee -a /etc/hosts
# wait for kube-apiserver oidc initialization
# (oidc authenticator will retry oidc discovery every 10s)
# Wait for kube-apiserver oidc initialization.
# oidc authenticator will retry oidc discovery every 10s.
sleep 10
# add the cluster role
# Add the cluster role.
kubectl create clusterrole cluster-readonly --verb=get,watch,list --resource='*.*'
kubectl create clusterrolebinding cluster-readonly --clusterrole=cluster-readonly --user=admin@example.com

View File

@@ -2,15 +2,18 @@ CERT_DIR := ../cert
.PHONY: dex
dex: dex.yaml
# wait for kind network
while true; do if docker network inspect kind; then break; fi; sleep 1; done
# create a container
# Wait for kind network.
until docker network inspect kind; do sleep 1; done
# Create a container.
docker create -q --name dex-server -p 10443:10443 --network kind ghcr.io/dexidp/dex:v2.39.0 dex serve /dex.yaml
# deploy the config
# Deploy the config.
docker cp $(CERT_DIR)/server.crt dex-server:/
docker cp $(CERT_DIR)/server.key dex-server:/
docker cp dex.yaml dex-server:/
# start the container
# Start the container.
docker start dex-server
docker logs dex-server

View File

@@ -29,6 +29,7 @@ test: build
--exec-arg=--oidc-client-id=YOUR_CLIENT_ID \
--exec-arg=--oidc-client-secret=YOUR_CLIENT_SECRET \
--exec-arg=--oidc-extra-scope=email \
--exec-arg=--token-cache-storage=keyring \
--exec-arg=--certificate-authority=$(CERT_DIR)/ca.crt \
--exec-arg=--browser-command=$(BIN_DIR)/chromelogin

View File

@@ -1,13 +0,0 @@
GOBIN := $(CURDIR)/bin
export GOBIN
all: bin/mockery bin/wire bin/golangci-lint
bin/mockery:
go install github.com/vektra/mockery/v2
bin/wire:
go install github.com/google/wire/cmd/wire
bin/golangci-lint:
go install github.com/golangci/golangci-lint/cmd/golangci-lint

View File

@@ -1,205 +0,0 @@
module github.com/int128/kubelogin/tools
go 1.23.5
require (
github.com/golangci/golangci-lint v1.63.4
github.com/google/wire v0.6.0
github.com/vektra/mockery/v2 v2.51.0
)
require (
4d63.com/gocheckcompilerdirectives v1.2.1 // indirect
4d63.com/gochecknoglobals v0.2.1 // indirect
github.com/4meepo/tagalign v1.4.1 // indirect
github.com/Abirdcfly/dupword v0.1.3 // indirect
github.com/Antonboom/errname v1.0.0 // indirect
github.com/Antonboom/nilnil v1.0.1 // indirect
github.com/Antonboom/testifylint v1.5.2 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/Crocmagnon/fatcontext v0.5.3 // indirect
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
github.com/alexkohler/nakedret/v2 v2.0.5 // indirect
github.com/alexkohler/prealloc v1.0.0 // indirect
github.com/alingse/asasalint v0.0.11 // indirect
github.com/alingse/nilnesserr v0.1.1 // indirect
github.com/ashanbrown/forbidigo v1.6.0 // indirect
github.com/ashanbrown/makezero v1.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bkielbasa/cyclop v1.2.3 // indirect
github.com/blizzy78/varnamelen v0.8.0 // indirect
github.com/bombsimon/wsl/v4 v4.5.0 // indirect
github.com/breml/bidichk v0.3.2 // indirect
github.com/breml/errchkjson v0.4.0 // indirect
github.com/butuzov/ireturn v0.3.1 // indirect
github.com/butuzov/mirror v1.3.0 // indirect
github.com/catenacyber/perfsprint v0.7.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/charithe/durationcheck v0.0.10 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/chigopher/pathlib v0.19.1 // indirect
github.com/ckaznocha/intrange v0.3.0 // indirect
github.com/curioswitch/go-reassign v0.3.0 // indirect
github.com/daixiang0/gci v0.13.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
github.com/ettle/strcase v0.2.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/firefart/nonamedreturns v1.0.5 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/ghostiam/protogetter v0.3.8 // indirect
github.com/go-critic/go-critic v0.11.5 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
github.com/go-toolsmith/astcopy v1.1.0 // indirect
github.com/go-toolsmith/astequal v1.2.0 // indirect
github.com/go-toolsmith/astfmt v1.1.0 // indirect
github.com/go-toolsmith/astp v1.1.0 // indirect
github.com/go-toolsmith/strparse v1.1.0 // indirect
github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
github.com/golangci/go-printf-func-name v0.1.0 // indirect
github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9 // indirect
github.com/golangci/misspell v0.6.0 // indirect
github.com/golangci/plugin-module-register v0.1.1 // indirect
github.com/golangci/revgrep v0.5.3 // indirect
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/subcommands v1.2.0 // indirect
github.com/gordonklaus/ineffassign v0.1.0 // indirect
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
github.com/gostaticanalysis/comment v1.4.2 // indirect
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/iancoleman/strcase v0.2.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jgautheron/goconst v1.7.1 // indirect
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/jjti/go-spancheck v0.6.4 // indirect
github.com/julz/importas v0.2.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect
github.com/kisielk/errcheck v1.8.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.5 // indirect
github.com/kulti/thelper v0.6.3 // indirect
github.com/kunwardeep/paralleltest v1.0.10 // indirect
github.com/kyoh86/exportloopref v0.1.11 // indirect
github.com/lasiar/canonicalheader v1.1.2 // indirect
github.com/ldez/exptostd v0.3.1 // indirect
github.com/ldez/gomoddirectives v0.6.0 // indirect
github.com/ldez/grignotin v0.7.0 // indirect
github.com/ldez/tagliatelle v0.7.1 // indirect
github.com/ldez/usetesting v0.4.2 // indirect
github.com/leonklingele/grouper v1.1.2 // indirect
github.com/macabu/inamedparam v0.1.3 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/maratori/testableexamples v1.0.0 // indirect
github.com/maratori/testpackage v1.1.1 // indirect
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mgechev/revive v1.5.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moricho/tparallel v0.3.2 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/nishanths/exhaustive v0.12.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nunnatsa/ginkgolinter v0.18.4 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polyfloyd/go-errorlint v1.7.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect
github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect
github.com/quasilyte/gogrep v0.5.0 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/raeperd/recvcheck v0.2.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/rs/zerolog v1.29.0 // indirect
github.com/ryancurrah/gomodguard v1.3.5 // indirect
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
github.com/sashamelentyev/usestdlibvars v1.28.0 // indirect
github.com/securego/gosec/v2 v2.21.4 // indirect
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sivchari/tenv v1.12.1 // indirect
github.com/sonatard/noctx v0.1.0 // indirect
github.com/sourcegraph/go-diff v0.7.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.15.0 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/tdakkota/asciicheck v0.3.0 // indirect
github.com/tetafro/godot v1.4.20 // indirect
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 // indirect
github.com/timonwong/loggercheck v0.10.1 // indirect
github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
github.com/ultraware/funlen v0.2.0 // indirect
github.com/ultraware/whitespace v0.2.0 // indirect
github.com/uudashr/gocognit v1.2.0 // indirect
github.com/uudashr/iface v1.3.0 // indirect
github.com/xen0n/gosmopolitan v1.2.2 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.3.0 // indirect
github.com/ykadowak/zerologlint v0.1.5 // indirect
gitlab.com/bosi/decorder v0.4.2 // indirect
go-simpler.org/musttag v0.13.0 // indirect
go-simpler.org/sloglint v0.7.2 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.16.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/tools v0.28.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.5.1 // indirect
mvdan.cc/gofumpt v0.7.0 // indirect
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +0,0 @@
//go:build tools
package main
import (
_ "github.com/google/wire/cmd/wire"
_ "github.com/vektra/mockery/v2/cmd"
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
)