mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-25 14:08:09 +02:00
Merge branch 'main' into kenjenkins/deprecate-jwt-endpoint
This commit is contained in:
commit
c36043f67f
43 changed files with 553 additions and 222 deletions
2
.github/Dockerfile-cloudrun
vendored
2
.github/Dockerfile-cloudrun
vendored
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
FROM busybox:latest@sha256:9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7 as build
|
FROM busybox:latest@sha256:82742949a3709938cbeb9cec79f5eaf3e48b255389f2dcedf2de29ef96fd841c as build
|
||||||
RUN touch /config.yaml
|
RUN touch /config.yaml
|
||||||
|
|
||||||
FROM gcr.io/distroless/base:latest@sha256:1aae189e3baecbb4044c648d356ddb75025b2ba8d14cdc9c2a19ba784c90bfb9
|
FROM gcr.io/distroless/base:latest@sha256:1aae189e3baecbb4044c648d356ddb75025b2ba8d14cdc9c2a19ba784c90bfb9
|
||||||
|
|
2
.github/Dockerfile-release
vendored
2
.github/Dockerfile-release
vendored
|
@ -1,4 +1,4 @@
|
||||||
FROM busybox:latest@sha256:9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7 as build
|
FROM busybox:latest@sha256:82742949a3709938cbeb9cec79f5eaf3e48b255389f2dcedf2de29ef96fd841c as build
|
||||||
RUN touch /config.yaml
|
RUN touch /config.yaml
|
||||||
|
|
||||||
FROM gcr.io/distroless/base-debian12:latest@sha256:1aae189e3baecbb4044c648d356ddb75025b2ba8d14cdc9c2a19ba784c90bfb9
|
FROM gcr.io/distroless/base-debian12:latest@sha256:1aae189e3baecbb4044c648d356ddb75025b2ba8d14cdc9c2a19ba784c90bfb9
|
||||||
|
|
2
.github/Dockerfile-release-debug
vendored
2
.github/Dockerfile-release-debug
vendored
|
@ -1,4 +1,4 @@
|
||||||
FROM busybox:latest@sha256:9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7 as build
|
FROM busybox:latest@sha256:82742949a3709938cbeb9cec79f5eaf3e48b255389f2dcedf2de29ef96fd841c as build
|
||||||
RUN touch /config.yaml
|
RUN touch /config.yaml
|
||||||
|
|
||||||
FROM gcr.io/distroless/base-debian12:debug@sha256:af772ed0ce52d8994acedc3ec84a9d22e9366dda8767f17d1bb2213b06beaff5
|
FROM gcr.io/distroless/base-debian12:debug@sha256:af772ed0ce52d8994acedc3ec84a9d22e9366dda8767f17d1bb2213b06beaff5
|
||||||
|
|
2
.github/Dockerfile-release-debug-nonroot
vendored
2
.github/Dockerfile-release-debug-nonroot
vendored
|
@ -1,4 +1,4 @@
|
||||||
FROM busybox:latest@sha256:9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7 as build
|
FROM busybox:latest@sha256:82742949a3709938cbeb9cec79f5eaf3e48b255389f2dcedf2de29ef96fd841c as build
|
||||||
RUN touch /config.yaml
|
RUN touch /config.yaml
|
||||||
|
|
||||||
FROM gcr.io/distroless/base-debian12:debug-nonroot@sha256:8d946e4103571ec0e2f471eac7c4859a7f169686d222f5c8b2d9d391d6d1e50c
|
FROM gcr.io/distroless/base-debian12:debug-nonroot@sha256:8d946e4103571ec0e2f471eac7c4859a7f169686d222f5c8b2d9d391d6d1e50c
|
||||||
|
|
2
.github/Dockerfile-release-nonroot
vendored
2
.github/Dockerfile-release-nonroot
vendored
|
@ -1,4 +1,4 @@
|
||||||
FROM busybox:latest@sha256:9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7 as build
|
FROM busybox:latest@sha256:82742949a3709938cbeb9cec79f5eaf3e48b255389f2dcedf2de29ef96fd841c as build
|
||||||
RUN touch /config.yaml
|
RUN touch /config.yaml
|
||||||
|
|
||||||
FROM gcr.io/distroless/base-debian12:nonroot@sha256:a9899ccd9868bbd8913c67f6807410abecf766bc9e3c718eb6248f7b3dfb9819
|
FROM gcr.io/distroless/base-debian12:nonroot@sha256:a9899ccd9868bbd8913c67f6807410abecf766bc9e3c718eb6248f7b3dfb9819
|
||||||
|
|
6
.github/workflows/docker-main.yaml
vendored
6
.github/workflows/docker-main.yaml
vendored
|
@ -45,7 +45,7 @@ jobs:
|
||||||
echo "sha-tag=${SHA_TAG}" >> $GITHUB_OUTPUT
|
echo "sha-tag=${SHA_TAG}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Docker Publish - Main
|
- name: Docker Publish - Main
|
||||||
uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445
|
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
@ -58,7 +58,7 @@ jobs:
|
||||||
org.opencontainers.image.revision=${{ github.sha }}
|
org.opencontainers.image.revision=${{ github.sha }}
|
||||||
|
|
||||||
- name: Docker Publish - Debug
|
- name: Docker Publish - Debug
|
||||||
uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445
|
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile.debug
|
file: ./Dockerfile.debug
|
||||||
|
@ -81,7 +81,7 @@ jobs:
|
||||||
token: ${{ secrets.APPARITOR_GITHUB_TOKEN }}
|
token: ${{ secrets.APPARITOR_GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Bump psql environment
|
- name: Bump psql environment
|
||||||
uses: mikefarah/yq@f15500b20a1c991c8729870ba60a4dc3524b6a94
|
uses: mikefarah/yq@bbdd97482f2d439126582a59689eb1c855944955
|
||||||
with:
|
with:
|
||||||
cmd:
|
cmd:
|
||||||
yq eval '.pomerium.image.tag = "${{ needs.publish.outputs.sha-tag }}"' -i
|
yq eval '.pomerium.image.tag = "${{ needs.publish.outputs.sha-tag }}"' -i
|
||||||
|
|
|
@ -38,7 +38,7 @@ jobs:
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Docker Publish - Version Branches
|
- name: Docker Publish - Version Branches
|
||||||
uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445
|
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|
6
.github/workflows/release.yaml
vendored
6
.github/workflows/release.yaml
vendored
|
@ -45,13 +45,13 @@ jobs:
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: gcloud authenticate
|
- name: gcloud authenticate
|
||||||
uses: google-github-actions/auth@71fee32a0bb7e97b4d33d548e7d957010649d8fa
|
uses: google-github-actions/auth@62cf5bd3e4211a0a0b51f2c6d6a37129d828611d
|
||||||
with:
|
with:
|
||||||
project_id: ${{ secrets.GCP_PRODUCTION_PROJECT_ID }}
|
project_id: ${{ secrets.GCP_PRODUCTION_PROJECT_ID }}
|
||||||
credentials_json: ${{ secrets.GCP_SERVICE_ACCOUNT }}
|
credentials_json: ${{ secrets.GCP_SERVICE_ACCOUNT }}
|
||||||
|
|
||||||
- name: gcloud sdk
|
- name: gcloud sdk
|
||||||
uses: google-github-actions/setup-gcloud@98ddc00a17442e89a24bbf282954a3b65ce6d200
|
uses: google-github-actions/setup-gcloud@f0990588f1e5b5af6827153b93673613abdc6ec7
|
||||||
|
|
||||||
- name: Gcloud login
|
- name: Gcloud login
|
||||||
run: gcloud auth configure-docker
|
run: gcloud auth configure-docker
|
||||||
|
@ -127,7 +127,7 @@ jobs:
|
||||||
token: ${{ secrets.APPARITOR_GITHUB_TOKEN }}
|
token: ${{ secrets.APPARITOR_GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Bump test environment
|
- name: Bump test environment
|
||||||
uses: mikefarah/yq@f15500b20a1c991c8729870ba60a4dc3524b6a94
|
uses: mikefarah/yq@bbdd97482f2d439126582a59689eb1c855944955
|
||||||
with:
|
with:
|
||||||
cmd: yq eval '.pomerium.image.tag = "${{ needs.goreleaser.outputs.tag }}"' -i projects/pomerium-demo/pomerium-demo/values.yaml
|
cmd: yq eval '.pomerium.image.tag = "${{ needs.goreleaser.outputs.tag }}"' -i projects/pomerium-demo/pomerium-demo/values.yaml
|
||||||
|
|
||||||
|
|
6
.github/workflows/test.yaml
vendored
6
.github/workflows/test.yaml
vendored
|
@ -76,7 +76,7 @@ jobs:
|
||||||
make build
|
make build
|
||||||
|
|
||||||
- name: save binary
|
- name: save binary
|
||||||
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
|
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874
|
||||||
with:
|
with:
|
||||||
path: bin/pomerium*
|
path: bin/pomerium*
|
||||||
name: pomerium ${{ github.run_id }} ${{ matrix.platform }}
|
name: pomerium ${{ github.run_id }} ${{ matrix.platform }}
|
||||||
|
@ -108,7 +108,7 @@ jobs:
|
||||||
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db
|
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db
|
||||||
|
|
||||||
- name: Docker Build
|
- name: Docker Build
|
||||||
uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445
|
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
@ -129,7 +129,7 @@ jobs:
|
||||||
go-version: 1.23.x
|
go-version: 1.23.x
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
- uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f
|
- uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3
|
||||||
with:
|
with:
|
||||||
python-version: "3.x"
|
python-version: "3.x"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:lts-bookworm@sha256:1ae9ba874435551280e95c8a8e74adf8a48d72b564bf9dfe4718231f2144c88f as ui
|
FROM node:lts-bookworm@sha256:a4d1de4c7339eabcf78a90137dfd551b798829e3ef3e399e0036ac454afa1291 as ui
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
COPY .git ./.git
|
COPY .git ./.git
|
||||||
|
@ -13,7 +13,7 @@ RUN make yarn
|
||||||
COPY ./ui/ ./ui/
|
COPY ./ui/ ./ui/
|
||||||
RUN make build-ui
|
RUN make build-ui
|
||||||
|
|
||||||
FROM golang:1.23-bookworm@sha256:4bda3420962ddfc78467f81eb9c2880e29e53604c6c05eae597210fc0fe8b5bf as build
|
FROM golang:1.23-bookworm@sha256:31dc846dd1bcca84d2fa231bcd16c09ff271bcc1a5ae2c48ff10f13b039688f3 as build
|
||||||
WORKDIR /go/src/github.com/pomerium/pomerium
|
WORKDIR /go/src/github.com/pomerium/pomerium
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:lts-bookworm@sha256:1ae9ba874435551280e95c8a8e74adf8a48d72b564bf9dfe4718231f2144c88f as ui
|
FROM node:lts-bookworm@sha256:a4d1de4c7339eabcf78a90137dfd551b798829e3ef3e399e0036ac454afa1291 as ui
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
COPY .git ./.git
|
COPY .git ./.git
|
||||||
|
@ -13,7 +13,7 @@ RUN make yarn
|
||||||
COPY ./ui/ ./ui/
|
COPY ./ui/ ./ui/
|
||||||
RUN make build-ui
|
RUN make build-ui
|
||||||
|
|
||||||
FROM golang:1.23-bookworm@sha256:4bda3420962ddfc78467f81eb9c2880e29e53604c6c05eae597210fc0fe8b5bf as build
|
FROM golang:1.23-bookworm@sha256:31dc846dd1bcca84d2fa231bcd16c09ff271bcc1a5ae2c48ff10f13b039688f3 as build
|
||||||
WORKDIR /go/src/github.com/pomerium/pomerium
|
WORKDIR /go/src/github.com/pomerium/pomerium
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
|
|
|
@ -14,7 +14,7 @@ Pomerium is:
|
||||||
- **Safer** because [every single action is verified](https://www.pomerium.com/continuous-verification-auditing) before allowed to execute.
|
- **Safer** because [every single action is verified](https://www.pomerium.com/continuous-verification-auditing) before allowed to execute.
|
||||||
- **Tailored** to your organization’s needs by integrating all data for [context-aware access](https://www.pomerium.com/context-aware-access).
|
- **Tailored** to your organization’s needs by integrating all data for [context-aware access](https://www.pomerium.com/context-aware-access).
|
||||||
|
|
||||||
It’s not a VPN alternative – it’s the trusted, foolproof way to protect your business. [Give Pomerium a try today](https://console.pomerium.app/create-account?utm_source=github&utm_medium=readme&utm_campaign=github)!
|
It’s not a VPN alternative – it’s the trusted, foolproof way to protect your business. Want a hosted control plane and management GUI? [Give Pomerium Zero a try today](https://console.pomerium.app/create-account?utm_source=github&utm_medium=readme&utm_campaign=github)!
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
|
|
||||||
|
|
|
@ -3,20 +3,22 @@ package config
|
||||||
import "maps"
|
import "maps"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// RuntimeFlagGRPCDatabrokerKeepalive enables gRPC keepalive to the databroker service
|
|
||||||
RuntimeFlagGRPCDatabrokerKeepalive = runtimeFlag("grpc_databroker_keepalive", false)
|
|
||||||
|
|
||||||
// RuntimeFlagMatchAnyIncomingPort enables ignoring the incoming port when matching routes
|
|
||||||
RuntimeFlagMatchAnyIncomingPort = runtimeFlag("match_any_incoming_port", true)
|
|
||||||
|
|
||||||
// RuntimeFlagLegacyIdentityManager enables the legacy identity manager
|
|
||||||
RuntimeFlagLegacyIdentityManager = runtimeFlag("legacy_identity_manager", false)
|
|
||||||
|
|
||||||
// RuntimeFlagConfigHotReload enables the hot-reloading mechanism for the config file
|
// RuntimeFlagConfigHotReload enables the hot-reloading mechanism for the config file
|
||||||
// and any other files referenced within it
|
// and any other files referenced within it
|
||||||
RuntimeFlagConfigHotReload = runtimeFlag("config_hot_reload", true)
|
RuntimeFlagConfigHotReload = runtimeFlag("config_hot_reload", true)
|
||||||
|
|
||||||
RuntimeFlagEnvoyResourceManagerEnabled = runtimeFlag("envoy_resource_manager_enabled", true)
|
// RuntimeFlagEnvoyResourceManager enables Envoy overload settings based on
|
||||||
|
// process cgroup limits (Linux only).
|
||||||
|
RuntimeFlagEnvoyResourceManager = runtimeFlag("envoy_resource_manager", true)
|
||||||
|
|
||||||
|
// RuntimeFlagGRPCDatabrokerKeepalive enables gRPC keepalive to the databroker service
|
||||||
|
RuntimeFlagGRPCDatabrokerKeepalive = runtimeFlag("grpc_databroker_keepalive", false)
|
||||||
|
|
||||||
|
// RuntimeFlagLegacyIdentityManager enables the legacy identity manager
|
||||||
|
RuntimeFlagLegacyIdentityManager = runtimeFlag("legacy_identity_manager", false)
|
||||||
|
|
||||||
|
// RuntimeFlagMatchAnyIncomingPort enables ignoring the incoming port when matching routes
|
||||||
|
RuntimeFlagMatchAnyIncomingPort = runtimeFlag("match_any_incoming_port", true)
|
||||||
|
|
||||||
// RuntimeFlagPomeriumJWTEndpoint enables the /.pomerium/jwt endpoint, for retrieving
|
// RuntimeFlagPomeriumJWTEndpoint enables the /.pomerium/jwt endpoint, for retrieving
|
||||||
// signed user info claims from an upstream single-page web application. This endpoint
|
// signed user info claims from an upstream single-page web application. This endpoint
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -180,7 +180,7 @@ require (
|
||||||
github.com/onsi/gomega v1.30.0 // indirect
|
github.com/onsi/gomega v1.30.0 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||||
github.com/opencontainers/runc v1.1.12 // indirect
|
github.com/opencontainers/runc v1.1.14 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/philhofer/fwd v1.1.2 // indirect
|
github.com/philhofer/fwd v1.1.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -489,8 +489,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||||
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
|
github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w=
|
||||||
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
|
github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA=
|
||||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||||
github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
|
github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg=
|
||||||
github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c=
|
github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c=
|
||||||
|
|
|
@ -63,7 +63,7 @@ func NewAPI(ctx context.Context, opts ...Option) (*API, error) {
|
||||||
|
|
||||||
tokenCache := token_api.NewCache(fetcher, cfg.apiToken)
|
tokenCache := token_api.NewCache(fetcher, cfg.apiToken)
|
||||||
|
|
||||||
clusterClient, err := cluster_api.NewAuthorizedClient(cfg.clusterAPIEndpoint, tokenCache.GetToken, cfg.httpClient)
|
clusterClient, err := cluster_api.NewAuthorizedClient(cfg.clusterAPIEndpoint, tokenCache, cfg.httpClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error creating cluster client: %w", err)
|
return nil, fmt.Errorf("error creating cluster client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -104,14 +104,14 @@ func (api *API) Watch(ctx context.Context, opts ...WatchOption) error {
|
||||||
|
|
||||||
// GetClusterBootstrapConfig fetches the bootstrap configuration from the cluster API
|
// GetClusterBootstrapConfig fetches the bootstrap configuration from the cluster API
|
||||||
func (api *API) GetClusterBootstrapConfig(ctx context.Context) (*cluster_api.BootstrapConfig, error) {
|
func (api *API) GetClusterBootstrapConfig(ctx context.Context) (*cluster_api.BootstrapConfig, error) {
|
||||||
return apierror.CheckResponse[cluster_api.BootstrapConfig](
|
return apierror.CheckResponse(
|
||||||
api.cluster.GetClusterBootstrapConfigWithResponse(ctx),
|
api.cluster.GetClusterBootstrapConfigWithResponse(ctx),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClusterResourceBundles fetches the resource bundles from the cluster API
|
// GetClusterResourceBundles fetches the resource bundles from the cluster API
|
||||||
func (api *API) GetClusterResourceBundles(ctx context.Context) (*cluster_api.GetBundlesResponse, error) {
|
func (api *API) GetClusterResourceBundles(ctx context.Context) (*cluster_api.GetBundlesResponse, error) {
|
||||||
return apierror.CheckResponse[cluster_api.GetBundlesResponse](
|
return apierror.CheckResponse(
|
||||||
api.cluster.GetClusterResourceBundlesWithResponse(ctx),
|
api.cluster.GetClusterResourceBundlesWithResponse(ctx),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,10 @@ func (api *API) DownloadClusterResourceBundle(
|
||||||
return newContentNotModifiedDownloadResult(resp.Header.Get("Last-Modified") != current.LastModified), nil
|
return newContentNotModifiedDownloadResult(resp.Header.Get("Last-Modified") != current.LastModified), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusUnauthorized {
|
||||||
|
api.downloadURLCache.Delete(id)
|
||||||
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return nil, httpDownloadError(ctx, resp)
|
return nil, httpDownloadError(ctx, resp)
|
||||||
}
|
}
|
||||||
|
@ -107,6 +111,10 @@ func (api *API) HeadClusterResourceBundle(
|
||||||
Str("status", resp.Status).
|
Str("status", resp.Status).
|
||||||
Msg("bundle metadata request")
|
Msg("bundle metadata request")
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusUnauthorized {
|
||||||
|
api.downloadURLCache.Delete(id)
|
||||||
|
}
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return nil, httpDownloadError(ctx, resp)
|
return nil, httpDownloadError(ctx, resp)
|
||||||
}
|
}
|
||||||
|
@ -180,7 +188,7 @@ func (api *API) getDownloadParams(ctx context.Context, id string) (*cluster_api.
|
||||||
func (api *API) updateBundleDownloadParams(ctx context.Context, id string) (*cluster_api.DownloadCacheEntry, error) {
|
func (api *API) updateBundleDownloadParams(ctx context.Context, id string) (*cluster_api.DownloadCacheEntry, error) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
resp, err := apierror.CheckResponse[cluster_api.DownloadBundleResponse](
|
resp, err := apierror.CheckResponse(
|
||||||
api.cluster.DownloadClusterResourceBundleWithResponse(ctx, id),
|
api.cluster.DownloadClusterResourceBundleWithResponse(ctx, id),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -197,11 +205,13 @@ func (api *API) updateBundleDownloadParams(ctx context.Context, id string) (*clu
|
||||||
return nil, fmt.Errorf("parse url: %w", err)
|
return nil, fmt.Errorf("parse url: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expires := now.Add(time.Duration(expiresSeconds) * time.Second)
|
||||||
param := cluster_api.DownloadCacheEntry{
|
param := cluster_api.DownloadCacheEntry{
|
||||||
URL: *u,
|
URL: *u,
|
||||||
ExpiresAt: now.Add(time.Duration(expiresSeconds) * time.Second),
|
ExpiresAt: expires,
|
||||||
CaptureHeaders: resp.CaptureMetadataHeaders,
|
CaptureHeaders: resp.CaptureMetadataHeaders,
|
||||||
}
|
}
|
||||||
|
log.Ctx(ctx).Debug().Time("expires", expires).Msg("bundle download URL updated")
|
||||||
api.downloadURLCache.Set(id, param)
|
api.downloadURLCache.Set(id, param)
|
||||||
return ¶m, nil
|
return ¶m, nil
|
||||||
}
|
}
|
||||||
|
@ -323,7 +333,7 @@ func isXML(ct string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractMetadata(header http.Header, keys []string) map[string]string {
|
func extractMetadata(header http.Header, keys []string) map[string]string {
|
||||||
log.Info().Interface("header", header).Msg("extract metadata")
|
log.Debug().Interface("header", header).Msg("extract metadata")
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
v := header.Get(k)
|
v := header.Get(k)
|
||||||
|
|
|
@ -47,6 +47,19 @@ func responseError[T any](resp APIResponse[T]) error {
|
||||||
if ok {
|
if ok {
|
||||||
return fmt.Errorf("internal server error: %v", reason)
|
return fmt.Errorf("internal server error: %v", reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f, ok := resp.(interface{ GetForbiddenError() (string, bool) }); ok {
|
||||||
|
if reason, ok := f.GetForbiddenError(); ok {
|
||||||
|
return fmt.Errorf("forbidden: %v", reason)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f, ok := resp.(interface{ GetNotFoundError() (string, bool) }); ok {
|
||||||
|
if reason, ok := f.GetNotFoundError(); ok {
|
||||||
|
return fmt.Errorf("not found: %v", reason)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//nolint:bodyclose
|
//nolint:bodyclose
|
||||||
httpResp := resp.GetHTTPResponse()
|
httpResp := resp.GetHTTPResponse()
|
||||||
if httpResp == nil {
|
if httpResp == nil {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package token
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -21,7 +20,7 @@ type Cache struct {
|
||||||
fetcher Fetcher
|
fetcher Fetcher
|
||||||
|
|
||||||
lock chan struct{}
|
lock chan struct{}
|
||||||
token atomic.Value
|
token atomic.Pointer[Token]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetcher is a function that fetches a new token
|
// Fetcher is a function that fetches a new token
|
||||||
|
@ -42,11 +41,13 @@ func (t *Token) ExpiresAfter(tm time.Time) bool {
|
||||||
|
|
||||||
// NewCache creates a new token cache
|
// NewCache creates a new token cache
|
||||||
func NewCache(fetcher Fetcher, refreshToken string) *Cache {
|
func NewCache(fetcher Fetcher, refreshToken string) *Cache {
|
||||||
return &Cache{
|
c := &Cache{
|
||||||
lock: make(chan struct{}, 1),
|
lock: make(chan struct{}, 1),
|
||||||
fetcher: fetcher,
|
fetcher: fetcher,
|
||||||
refreshToken: refreshToken,
|
refreshToken: refreshToken,
|
||||||
}
|
}
|
||||||
|
c.token.Store(nil)
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) timeNow() time.Time {
|
func (c *Cache) timeNow() time.Time {
|
||||||
|
@ -56,19 +57,33 @@ func (c *Cache) timeNow() time.Time {
|
||||||
return time.Now()
|
return time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cache) Reset() {
|
||||||
|
c.token.Store(nil)
|
||||||
|
}
|
||||||
|
|
||||||
// GetToken returns the current token if its at least `minTTL` from expiration, or fetches a new one.
|
// GetToken returns the current token if its at least `minTTL` from expiration, or fetches a new one.
|
||||||
func (c *Cache) GetToken(ctx context.Context, minTTL time.Duration) (string, error) {
|
func (c *Cache) GetToken(ctx context.Context, minTTL time.Duration) (string, error) {
|
||||||
minExpiration := c.timeNow().Add(minTTL)
|
minExpiration := c.timeNow().Add(minTTL)
|
||||||
|
|
||||||
token, ok := c.token.Load().(*Token)
|
token := c.token.Load()
|
||||||
if ok && token.ExpiresAfter(minExpiration) {
|
if token.ExpiresAfter(minExpiration) {
|
||||||
return token.Bearer, nil
|
return token.Bearer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.forceRefreshToken(ctx, minExpiration)
|
return c.ForceRefreshToken(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) forceRefreshToken(ctx context.Context, minExpiration time.Time) (string, error) {
|
func (c *Cache) ForceRefreshToken(ctx context.Context) (string, error) {
|
||||||
|
var current string
|
||||||
|
token := c.token.Load()
|
||||||
|
if token != nil {
|
||||||
|
current = token.Bearer
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.forceRefreshToken(ctx, current)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) forceRefreshToken(ctx context.Context, current string) (string, error) {
|
||||||
select {
|
select {
|
||||||
case c.lock <- struct{}{}:
|
case c.lock <- struct{}{}:
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
@ -81,8 +96,8 @@ func (c *Cache) forceRefreshToken(ctx context.Context, minExpiration time.Time)
|
||||||
ctx, cancel := context.WithTimeout(ctx, maxLockWait)
|
ctx, cancel := context.WithTimeout(ctx, maxLockWait)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
token, ok := c.token.Load().(*Token)
|
token := c.token.Load()
|
||||||
if ok && token.ExpiresAfter(minExpiration) {
|
if token != nil && token.Bearer != current {
|
||||||
return token.Bearer, nil
|
return token.Bearer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +107,5 @@ func (c *Cache) forceRefreshToken(ctx context.Context, minExpiration time.Time)
|
||||||
}
|
}
|
||||||
c.token.Store(token)
|
c.token.Store(token)
|
||||||
|
|
||||||
if token.Expires.Before(minExpiration) {
|
|
||||||
return "", fmt.Errorf("new token cannot satisfy TTL: %v", minExpiration.Sub(token.Expires))
|
|
||||||
}
|
|
||||||
|
|
||||||
return token.Bearer, nil
|
return token.Bearer, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package token_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -51,15 +52,28 @@ func TestCache(t *testing.T) {
|
||||||
assert.Equal(t, "bearer-3", bearer)
|
assert.Equal(t, "bearer-3", bearer)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("token cannot fit minTTL", func(t *testing.T) {
|
t.Run("reset", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
var calls int
|
||||||
fetcher := func(_ context.Context, _ string) (*token.Token, error) {
|
fetcher := func(_ context.Context, _ string) (*token.Token, error) {
|
||||||
return &token.Token{"ok-bearer", time.Now().Add(time.Minute)}, nil
|
calls++
|
||||||
|
return &token.Token{fmt.Sprintf("bearer-%d", calls), time.Now().Add(time.Hour)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
c := token.NewCache(fetcher, "test-refresh-token")
|
c := token.NewCache(fetcher, "test-refresh-token")
|
||||||
_, err := c.GetToken(context.Background(), time.Minute*2)
|
got, err := c.GetToken(ctx, time.Minute*2)
|
||||||
assert.Error(t, err)
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "bearer-1", got)
|
||||||
|
|
||||||
|
got, err = c.GetToken(ctx, time.Minute*2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "bearer-1", got)
|
||||||
|
|
||||||
|
c.Reset()
|
||||||
|
got, err = c.GetToken(ctx, time.Minute*2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "bearer-2", got)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: pomerium
|
name: pomerium
|
||||||
spec:
|
spec:
|
||||||
serviceName: "pomerium-proxy"
|
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app.kubernetes.io/name: pomerium-zero
|
app.kubernetes.io/name: pomerium-zero
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
|
serviceAccountName: pomerium-zero
|
||||||
containers:
|
containers:
|
||||||
- name: pomerium
|
- name: pomerium
|
||||||
terminationGracePeriodSeconds: 10
|
terminationGracePeriodSeconds: 10
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: pomerium
|
name: pomerium
|
||||||
spec:
|
spec:
|
||||||
|
@ -19,6 +19,10 @@ spec:
|
||||||
fieldRef:
|
fieldRef:
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
fieldPath: metadata.namespace
|
fieldPath: metadata.namespace
|
||||||
|
- name: BOOTSTRAP_CONFIG_FILE
|
||||||
|
value: "/var/run/secrets/pomerium/bootstrap.dat"
|
||||||
|
- name: BOOTSTRAP_CONFIG_WRITEBACK_URI
|
||||||
|
value: "secret://$(POMERIUM_NAMESPACE)/pomerium/bootstrap"
|
||||||
- name: POD_IP
|
- name: POD_IP
|
||||||
valueFrom:
|
valueFrom:
|
||||||
fieldRef:
|
fieldRef:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: pomerium
|
name: pomerium
|
||||||
spec:
|
spec:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: pomerium
|
name: pomerium
|
||||||
spec:
|
spec:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: pomerium
|
name: pomerium
|
||||||
spec:
|
spec:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: pomerium
|
name: pomerium
|
||||||
spec:
|
spec:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: pomerium
|
name: pomerium
|
||||||
spec:
|
spec:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: pomerium
|
name: pomerium
|
||||||
spec:
|
spec:
|
||||||
|
@ -13,22 +13,22 @@ spec:
|
||||||
- name: TMPDIR
|
- name: TMPDIR
|
||||||
value: "/tmp/pomerium"
|
value: "/tmp/pomerium"
|
||||||
- name: XDG_CACHE_HOME
|
- name: XDG_CACHE_HOME
|
||||||
value: "/var/cache"
|
value: "/tmp/pomerium/cache"
|
||||||
- name: XDG_DATA_HOME
|
- name: XDG_DATA_HOME
|
||||||
value: "/var/cache"
|
value: "/tmp/pomerium/cache"
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: "/tmp/pomerium"
|
- mountPath: "/tmp/pomerium"
|
||||||
name: tmp
|
name: tmp
|
||||||
- mountPath: "/var/cache"
|
- mountPath: "/var/run/secrets/pomerium"
|
||||||
name: pomerium-cache
|
name: bootstrap
|
||||||
|
readOnly: true
|
||||||
volumes:
|
volumes:
|
||||||
- name: tmp
|
- name: tmp
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
volumeClaimTemplates:
|
- name: bootstrap
|
||||||
- metadata:
|
secret:
|
||||||
name: pomerium-cache
|
optional: true
|
||||||
spec:
|
secretName: pomerium
|
||||||
accessModes: [ "ReadWriteOnce" ]
|
items:
|
||||||
resources:
|
- key: bootstrap
|
||||||
requests:
|
path: bootstrap.dat
|
||||||
storage: 100Mi
|
|
||||||
|
|
|
@ -3,5 +3,6 @@ commonLabels:
|
||||||
app.kubernetes.io/name: pomerium-zero
|
app.kubernetes.io/name: pomerium-zero
|
||||||
resources:
|
resources:
|
||||||
- namespace.yaml
|
- namespace.yaml
|
||||||
|
- ./rbac
|
||||||
- ./deployment
|
- ./deployment
|
||||||
- ./service
|
- ./service
|
||||||
|
|
6
k8s/zero/rbac/kustomization.yaml
Normal file
6
k8s/zero/rbac/kustomization.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- role.yaml
|
||||||
|
- role_binding.yaml
|
||||||
|
- service_account.yaml
|
14
k8s/zero/rbac/role.yaml
Normal file
14
k8s/zero/rbac/role.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: pomerium-zero
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- patch
|
||||||
|
resourceNames:
|
||||||
|
- pomerium
|
11
k8s/zero/rbac/role_binding.yaml
Normal file
11
k8s/zero/rbac/role_binding.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: pomerium-zero
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: pomerium-zero
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: pomerium-zero
|
4
k8s/zero/rbac/service_account.yaml
Normal file
4
k8s/zero/rbac/service_account.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: pomerium-zero
|
|
@ -204,10 +204,10 @@ type sharedResourceMonitor struct {
|
||||||
|
|
||||||
func (s *sharedResourceMonitor) onConfigChange(_ context.Context, cfg *config.Config) {
|
func (s *sharedResourceMonitor) onConfigChange(_ context.Context, cfg *config.Config) {
|
||||||
if cfg == nil || cfg.Options == nil {
|
if cfg == nil || cfg.Options == nil {
|
||||||
s.enabled.Store(config.DefaultRuntimeFlags()[config.RuntimeFlagEnvoyResourceManagerEnabled])
|
s.enabled.Store(config.DefaultRuntimeFlags()[config.RuntimeFlagEnvoyResourceManager])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.enabled.Store(cfg.Options.IsRuntimeFlagSet(config.RuntimeFlagEnvoyResourceManagerEnabled))
|
s.enabled.Store(cfg.Options.IsRuntimeFlagSet(config.RuntimeFlagEnvoyResourceManager))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sharedResourceMonitor) metricFilename(group, name string) string {
|
func (s *sharedResourceMonitor) metricFilename(group, name string) string {
|
||||||
|
|
|
@ -665,7 +665,7 @@ func TestSharedResourceMonitor(t *testing.T) {
|
||||||
configSrc.SetConfig(ctx, &config.Config{
|
configSrc.SetConfig(ctx, &config.Config{
|
||||||
Options: &config.Options{
|
Options: &config.Options{
|
||||||
RuntimeFlags: config.RuntimeFlags{
|
RuntimeFlags: config.RuntimeFlags{
|
||||||
config.RuntimeFlagEnvoyResourceManagerEnabled: false,
|
config.RuntimeFlagEnvoyResourceManager: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -677,7 +677,7 @@ func TestSharedResourceMonitor(t *testing.T) {
|
||||||
configSrc.SetConfig(ctx, &config.Config{
|
configSrc.SetConfig(ctx, &config.Config{
|
||||||
Options: &config.Options{
|
Options: &config.Options{
|
||||||
RuntimeFlags: config.RuntimeFlags{
|
RuntimeFlags: config.RuntimeFlags{
|
||||||
config.RuntimeFlagEnvoyResourceManagerEnabled: true,
|
config.RuntimeFlagEnvoyResourceManager: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
207
pkg/zero/cluster/client-with-responses.tmpl
Normal file
207
pkg/zero/cluster/client-with-responses.tmpl
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
{{/*
|
||||||
|
This file contains the original client-with-responses.tmpl, plus some additional
|
||||||
|
code to generate custom response functions.
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
{{/* Begin upstream code /*}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
// Copyright 2019 DeepMap, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
*/}}
|
||||||
|
|
||||||
|
// ClientWithResponses builds on ClientInterface to offer response payloads
|
||||||
|
type ClientWithResponses struct {
|
||||||
|
ClientInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientWithResponses creates a new ClientWithResponses, which wraps
|
||||||
|
// Client with return type handling
|
||||||
|
func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
|
||||||
|
client, err := NewClient(server, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ClientWithResponses{client}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
{{$clientTypeName := opts.OutputOptions.ClientTypeName -}}
|
||||||
|
|
||||||
|
// WithBaseURL overrides the baseURL.
|
||||||
|
func WithBaseURL(baseURL string) ClientOption {
|
||||||
|
return func(c *{{ $clientTypeName }}) error {
|
||||||
|
newBaseURL, err := url.Parse(baseURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Server = newBaseURL.String()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientWithResponsesInterface is the interface specification for the client with responses above.
|
||||||
|
type ClientWithResponsesInterface interface {
|
||||||
|
{{range . -}}
|
||||||
|
{{$hasParams := .RequiresParamObject -}}
|
||||||
|
{{$pathParams := .PathParams -}}
|
||||||
|
{{$opid := .OperationId -}}
|
||||||
|
// {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse request{{if .HasBody}} with any body{{end}}
|
||||||
|
{{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error)
|
||||||
|
{{range .Bodies}}
|
||||||
|
{{if .IsSupportedByClient -}}
|
||||||
|
{{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error)
|
||||||
|
{{end -}}
|
||||||
|
{{end}}{{/* range .Bodies */}}
|
||||||
|
{{end}}{{/* range . $opid := .OperationId */}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{range .}}{{$opid := .OperationId}}{{$op := .}}
|
||||||
|
type {{genResponseTypeName $opid | ucFirst}} struct {
|
||||||
|
Body []byte
|
||||||
|
HTTPResponse *http.Response
|
||||||
|
{{- range getResponseTypeDefinitions .}}
|
||||||
|
{{.TypeName}} *{{.Schema.TypeDecl}}
|
||||||
|
{{- end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status returns HTTPResponse.Status
|
||||||
|
func (r {{genResponseTypeName $opid | ucFirst}}) Status() string {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.Status
|
||||||
|
}
|
||||||
|
return http.StatusText(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusCode returns HTTPResponse.StatusCode
|
||||||
|
func (r {{genResponseTypeName $opid | ucFirst}}) StatusCode() int {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.StatusCode
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
|
||||||
|
{{range .}}
|
||||||
|
{{$opid := .OperationId -}}
|
||||||
|
{{/* Generate client methods (with responses)*/}}
|
||||||
|
|
||||||
|
// {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse request{{if .HasBody}} with arbitrary body{{end}} returning *{{genResponseTypeName $opid}}
|
||||||
|
func (c *ClientWithResponses) {{$opid}}{{if .HasBody}}WithBody{{end}}WithResponse(ctx context.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error){
|
||||||
|
rsp, err := c.{{$opid}}{{if .HasBody}}WithBody{{end}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}}{{if .HasBody}}, contentType, body{{end}}, reqEditors...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Parse{{genResponseTypeName $opid | ucFirst}}(rsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
{{$hasParams := .RequiresParamObject -}}
|
||||||
|
{{$pathParams := .PathParams -}}
|
||||||
|
{{$bodyRequired := .BodyRequired -}}
|
||||||
|
{{range .Bodies}}
|
||||||
|
{{if .IsSupportedByClient -}}
|
||||||
|
func (c *ClientWithResponses) {{$opid}}{{.Suffix}}WithResponse(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*{{genResponseTypeName $opid}}, error) {
|
||||||
|
rsp, err := c.{{$opid}}{{.Suffix}}(ctx{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body, reqEditors...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Parse{{genResponseTypeName $opid | ucFirst}}(rsp)
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{end}}{{/* operations */}}
|
||||||
|
|
||||||
|
{{/* Generate parse functions for responses*/}}
|
||||||
|
{{range .}}{{$opid := .OperationId}}
|
||||||
|
|
||||||
|
// Parse{{genResponseTypeName $opid | ucFirst}} parses an HTTP response from a {{$opid}}WithResponse call
|
||||||
|
func Parse{{genResponseTypeName $opid | ucFirst}}(rsp *http.Response) (*{{genResponseTypeName $opid}}, error) {
|
||||||
|
bodyBytes, err := io.ReadAll(rsp.Body)
|
||||||
|
defer func() { _ = rsp.Body.Close() }()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := {{genResponsePayload $opid}}
|
||||||
|
|
||||||
|
{{genResponseUnmarshal .}}
|
||||||
|
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
{{end}}{{/* range . $opid := .OperationId */}}
|
||||||
|
|
||||||
|
{{/* End upstream code /*}}
|
||||||
|
|
||||||
|
|
||||||
|
{{/* Custom code below */}}
|
||||||
|
|
||||||
|
{{range .}}{{$opid := .OperationId}}{{$op := .}}
|
||||||
|
// GetHTTPResponse implements apierror.APIResponse
|
||||||
|
func (r *{{genResponseTypeName $opid | ucFirst}}) GetHTTPResponse() *http.Response {
|
||||||
|
return r.HTTPResponse
|
||||||
|
}
|
||||||
|
{{- $has200Resp := false -}}
|
||||||
|
{{- range getResponseTypeDefinitions .}}
|
||||||
|
{{- if (eq .TypeName "JSON200")}}
|
||||||
|
{{- $has200Resp = true}}
|
||||||
|
// GetValue implements apierror.APIResponse
|
||||||
|
func (r *{{genResponseTypeName $opid | ucFirst}}) GetValue() *{{.Schema.TypeDecl}} {
|
||||||
|
return r.JSON200
|
||||||
|
}
|
||||||
|
{{- else if (eq .TypeName "JSON400")}}
|
||||||
|
// GetBadRequestError implements apierror.APIResponse
|
||||||
|
func (r *{{genResponseTypeName $opid | ucFirst}}) GetBadRequestError() (string, bool) {
|
||||||
|
if r.JSON400 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON400.Error, true
|
||||||
|
}
|
||||||
|
{{- else if (eq .TypeName "JSON404")}}
|
||||||
|
|
||||||
|
func (r *{{genResponseTypeName $opid | ucFirst}}) GetNotFoundError() (string, bool) {
|
||||||
|
if r.JSON404 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON404.Error, true
|
||||||
|
}
|
||||||
|
{{- else if (eq .TypeName "JSON403")}}
|
||||||
|
|
||||||
|
func (r *{{genResponseTypeName $opid | ucFirst}}) GetForbiddenError() (string, bool) {
|
||||||
|
if r.JSON403 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON403.Error, true
|
||||||
|
}
|
||||||
|
{{- else if (eq .TypeName "JSON500")}}
|
||||||
|
// GetInternalServerError implements apierror.APIResponse
|
||||||
|
func (r *{{genResponseTypeName $opid | ucFirst}}) GetInternalServerError() (string, bool) {
|
||||||
|
if r.JSON500 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON500.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
{{- end}}
|
||||||
|
{{- end}}
|
||||||
|
{{- if (not $has200Resp)}}
|
||||||
|
// GetValue implements apierror.APIResponse
|
||||||
|
func (r *{{genResponseTypeName $opid | ucFirst}}) GetValue() *EmptyResponse {
|
||||||
|
if r.StatusCode()/100 != 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &EmptyResponse{}
|
||||||
|
}
|
||||||
|
{{- end}}
|
||||||
|
{{end}}
|
|
@ -811,3 +811,143 @@ func ParseExchangeClusterIdentityTokenResp(rsp *http.Response) (*ExchangeCluster
|
||||||
|
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHTTPResponse implements apierror.APIResponse
|
||||||
|
func (r *GetClusterBootstrapConfigResp) GetHTTPResponse() *http.Response {
|
||||||
|
return r.HTTPResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue implements apierror.APIResponse
|
||||||
|
func (r *GetClusterBootstrapConfigResp) GetValue() *GetBootstrapConfigResponse {
|
||||||
|
return r.JSON200
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBadRequestError implements apierror.APIResponse
|
||||||
|
func (r *GetClusterBootstrapConfigResp) GetBadRequestError() (string, bool) {
|
||||||
|
if r.JSON400 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON400.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInternalServerError implements apierror.APIResponse
|
||||||
|
func (r *GetClusterBootstrapConfigResp) GetInternalServerError() (string, bool) {
|
||||||
|
if r.JSON500 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON500.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHTTPResponse implements apierror.APIResponse
|
||||||
|
func (r *GetClusterResourceBundlesResp) GetHTTPResponse() *http.Response {
|
||||||
|
return r.HTTPResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue implements apierror.APIResponse
|
||||||
|
func (r *GetClusterResourceBundlesResp) GetValue() *GetBundlesResponse {
|
||||||
|
return r.JSON200
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBadRequestError implements apierror.APIResponse
|
||||||
|
func (r *GetClusterResourceBundlesResp) GetBadRequestError() (string, bool) {
|
||||||
|
if r.JSON400 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON400.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInternalServerError implements apierror.APIResponse
|
||||||
|
func (r *GetClusterResourceBundlesResp) GetInternalServerError() (string, bool) {
|
||||||
|
if r.JSON500 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON500.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHTTPResponse implements apierror.APIResponse
|
||||||
|
func (r *DownloadClusterResourceBundleResp) GetHTTPResponse() *http.Response {
|
||||||
|
return r.HTTPResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue implements apierror.APIResponse
|
||||||
|
func (r *DownloadClusterResourceBundleResp) GetValue() *DownloadBundleResponse {
|
||||||
|
return r.JSON200
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBadRequestError implements apierror.APIResponse
|
||||||
|
func (r *DownloadClusterResourceBundleResp) GetBadRequestError() (string, bool) {
|
||||||
|
if r.JSON400 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON400.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DownloadClusterResourceBundleResp) GetNotFoundError() (string, bool) {
|
||||||
|
if r.JSON404 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON404.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInternalServerError implements apierror.APIResponse
|
||||||
|
func (r *DownloadClusterResourceBundleResp) GetInternalServerError() (string, bool) {
|
||||||
|
if r.JSON500 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON500.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHTTPResponse implements apierror.APIResponse
|
||||||
|
func (r *ReportClusterResourceBundleStatusResp) GetHTTPResponse() *http.Response {
|
||||||
|
return r.HTTPResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBadRequestError implements apierror.APIResponse
|
||||||
|
func (r *ReportClusterResourceBundleStatusResp) GetBadRequestError() (string, bool) {
|
||||||
|
if r.JSON400 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON400.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInternalServerError implements apierror.APIResponse
|
||||||
|
func (r *ReportClusterResourceBundleStatusResp) GetInternalServerError() (string, bool) {
|
||||||
|
if r.JSON500 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON500.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue implements apierror.APIResponse
|
||||||
|
func (r *ReportClusterResourceBundleStatusResp) GetValue() *EmptyResponse {
|
||||||
|
if r.StatusCode()/100 != 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &EmptyResponse{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHTTPResponse implements apierror.APIResponse
|
||||||
|
func (r *ExchangeClusterIdentityTokenResp) GetHTTPResponse() *http.Response {
|
||||||
|
return r.HTTPResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue implements apierror.APIResponse
|
||||||
|
func (r *ExchangeClusterIdentityTokenResp) GetValue() *ExchangeTokenResponse {
|
||||||
|
return r.JSON200
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBadRequestError implements apierror.APIResponse
|
||||||
|
func (r *ExchangeClusterIdentityTokenResp) GetBadRequestError() (string, bool) {
|
||||||
|
if r.JSON400 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON400.Error, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInternalServerError implements apierror.APIResponse
|
||||||
|
func (r *ExchangeClusterIdentityTokenResp) GetInternalServerError() (string, bool) {
|
||||||
|
if r.JSON500 == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return r.JSON500.Error, true
|
||||||
|
}
|
||||||
|
|
|
@ -17,18 +17,23 @@ const (
|
||||||
var userAgent = version.UserAgent()
|
var userAgent = version.UserAgent()
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
tokenProvider TokenProviderFn
|
tokenProvider TokenCache
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
minTokenTTL time.Duration
|
minTokenTTL time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenProviderFn is a function that returns a token that is expected to be valid for at least minTTL
|
// TokenCache interface for fetching and caching tokens
|
||||||
type TokenProviderFn func(ctx context.Context, minTTL time.Duration) (string, error)
|
type TokenCache interface {
|
||||||
|
// GetToken returns a token that is expected to be valid for at least minTTL duration
|
||||||
|
GetToken(ctx context.Context, minTTL time.Duration) (string, error)
|
||||||
|
// Reset resets the token cache
|
||||||
|
Reset()
|
||||||
|
}
|
||||||
|
|
||||||
// NewAuthorizedClient creates a new HTTP client that will automatically add an authorization header
|
// NewAuthorizedClient creates a new HTTP client that will automatically add an authorization header
|
||||||
func NewAuthorizedClient(
|
func NewAuthorizedClient(
|
||||||
endpoint string,
|
endpoint string,
|
||||||
tokenProvider TokenProviderFn,
|
tokenProvider TokenCache,
|
||||||
httpClient *http.Client,
|
httpClient *http.Client,
|
||||||
) (ClientWithResponsesInterface, error) {
|
) (ClientWithResponsesInterface, error) {
|
||||||
c := &client{
|
c := &client{
|
||||||
|
@ -43,12 +48,21 @@ func NewAuthorizedClient(
|
||||||
|
|
||||||
func (c *client) Do(req *http.Request) (*http.Response, error) {
|
func (c *client) Do(req *http.Request) (*http.Response, error) {
|
||||||
ctx := req.Context()
|
ctx := req.Context()
|
||||||
token, err := c.tokenProvider(ctx, c.minTokenTTL)
|
token, err := c.tokenProvider.GetToken(ctx, c.minTokenTTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error getting token: %w", err)
|
return nil, fmt.Errorf("error getting token: %w", err)
|
||||||
}
|
}
|
||||||
req.Header.Set("Authorization", "Bearer "+token)
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
req.Header.Set("User-Agent", userAgent)
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
|
||||||
return c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusUnauthorized {
|
||||||
|
c.tokenProvider.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,5 @@ output-options:
|
||||||
# We use Response suffix internally throughout the response objects,
|
# We use Response suffix internally throughout the response objects,
|
||||||
# that conflicts with generated client
|
# that conflicts with generated client
|
||||||
response-type-suffix: Resp
|
response-type-suffix: Resp
|
||||||
|
user-templates:
|
||||||
|
client-with-responses.tmpl: ./client-with-responses.tmpl
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package cluster
|
package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/internal/zero/apierror"
|
"github.com/pomerium/pomerium/internal/zero/apierror"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,133 +14,3 @@ var (
|
||||||
_ apierror.APIResponse[DownloadBundleResponse] = (*DownloadClusterResourceBundleResp)(nil)
|
_ apierror.APIResponse[DownloadBundleResponse] = (*DownloadClusterResourceBundleResp)(nil)
|
||||||
_ apierror.APIResponse[EmptyResponse] = (*ReportClusterResourceBundleStatusResp)(nil)
|
_ apierror.APIResponse[EmptyResponse] = (*ReportClusterResourceBundleStatusResp)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetBadRequestError implements apierror.APIResponse
|
|
||||||
func (r *ExchangeClusterIdentityTokenResp) GetBadRequestError() (string, bool) {
|
|
||||||
if r.JSON400 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON400.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInternalServerError implements apierror.APIResponse
|
|
||||||
func (r *ExchangeClusterIdentityTokenResp) GetInternalServerError() (string, bool) {
|
|
||||||
if r.JSON500 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON500.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValue implements apierror.APIResponse
|
|
||||||
func (r *ExchangeClusterIdentityTokenResp) GetValue() *ExchangeTokenResponse {
|
|
||||||
return r.JSON200
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPResponse implements apierror.APIResponse
|
|
||||||
func (r *ExchangeClusterIdentityTokenResp) GetHTTPResponse() *http.Response {
|
|
||||||
return r.HTTPResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBadRequestError implements apierror.APIResponse
|
|
||||||
func (r *GetClusterBootstrapConfigResp) GetBadRequestError() (string, bool) {
|
|
||||||
if r.JSON400 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON400.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInternalServerError implements apierror.APIResponse
|
|
||||||
func (r *GetClusterBootstrapConfigResp) GetInternalServerError() (string, bool) {
|
|
||||||
if r.JSON500 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON500.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValue implements apierror.APIResponse
|
|
||||||
func (r *GetClusterBootstrapConfigResp) GetValue() *BootstrapConfig {
|
|
||||||
return r.JSON200
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPResponse implements apierror.APIResponse
|
|
||||||
func (r *GetClusterBootstrapConfigResp) GetHTTPResponse() *http.Response {
|
|
||||||
return r.HTTPResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBadRequestError implements apierror.APIResponse
|
|
||||||
func (r *GetClusterResourceBundlesResp) GetBadRequestError() (string, bool) {
|
|
||||||
if r.JSON400 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON400.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInternalServerError implements apierror.APIResponse
|
|
||||||
func (r *GetClusterResourceBundlesResp) GetInternalServerError() (string, bool) {
|
|
||||||
if r.JSON500 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON500.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValue implements apierror.APIResponse
|
|
||||||
func (r *GetClusterResourceBundlesResp) GetValue() *GetBundlesResponse {
|
|
||||||
return r.JSON200
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPResponse implements apierror.APIResponse
|
|
||||||
func (r *GetClusterResourceBundlesResp) GetHTTPResponse() *http.Response {
|
|
||||||
return r.HTTPResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBadRequestError implements apierror.APIResponse
|
|
||||||
func (r *DownloadClusterResourceBundleResp) GetBadRequestError() (string, bool) {
|
|
||||||
if r.JSON400 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON400.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInternalServerError implements apierror.APIResponse
|
|
||||||
func (r *DownloadClusterResourceBundleResp) GetInternalServerError() (string, bool) {
|
|
||||||
if r.JSON500 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON500.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValue implements apierror.APIResponse
|
|
||||||
func (r *DownloadClusterResourceBundleResp) GetValue() *DownloadBundleResponse {
|
|
||||||
return r.JSON200
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPResponse implements apierror.APIResponse
|
|
||||||
func (r *DownloadClusterResourceBundleResp) GetHTTPResponse() *http.Response {
|
|
||||||
return r.HTTPResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBadRequestError implements apierror.APIResponse
|
|
||||||
func (r *ReportClusterResourceBundleStatusResp) GetBadRequestError() (string, bool) {
|
|
||||||
if r.JSON400 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON400.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInternalServerError implements apierror.APIResponse
|
|
||||||
func (r *ReportClusterResourceBundleStatusResp) GetInternalServerError() (string, bool) {
|
|
||||||
if r.JSON500 == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
return r.JSON500.Error, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetValue implements apierror.APIResponse
|
|
||||||
func (r *ReportClusterResourceBundleStatusResp) GetValue() *EmptyResponse {
|
|
||||||
return &EmptyResponse{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHTTPResponse implements apierror.APIResponse
|
|
||||||
func (r *ReportClusterResourceBundleStatusResp) GetHTTPResponse() *http.Response {
|
|
||||||
return r.HTTPResponse
|
|
||||||
}
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ func TestAPIClient(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tokenCache := token.NewCache(fetcher, "refresh-token")
|
tokenCache := token.NewCache(fetcher, "refresh-token")
|
||||||
client, err := api.NewAuthorizedClient(srv.URL, tokenCache.GetToken, http.DefaultClient)
|
client, err := api.NewAuthorizedClient(srv.URL, tokenCache, http.DefaultClient)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
resp, err := client.ExchangeClusterIdentityTokenWithResponse(context.Background(),
|
resp, err := client.ExchangeClusterIdentityTokenWithResponse(context.Background(),
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/internal/zero/apierror"
|
"github.com/pomerium/pomerium/internal/zero/apierror"
|
||||||
"github.com/pomerium/pomerium/internal/zero/token"
|
"github.com/pomerium/pomerium/internal/zero/token"
|
||||||
)
|
)
|
||||||
|
@ -20,7 +21,7 @@ func NewTokenFetcher(endpoint string, opts ...ClientOption) (token.Fetcher, erro
|
||||||
return func(ctx context.Context, refreshToken string) (*token.Token, error) {
|
return func(ctx context.Context, refreshToken string) (*token.Token, error) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
resp, err := apierror.CheckResponse[ExchangeTokenResponse](client.ExchangeClusterIdentityTokenWithResponse(ctx, ExchangeTokenRequest{
|
resp, err := apierror.CheckResponse(client.ExchangeClusterIdentityTokenWithResponse(ctx, ExchangeTokenRequest{
|
||||||
RefreshToken: refreshToken,
|
RefreshToken: refreshToken,
|
||||||
}))
|
}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -32,9 +33,11 @@ func NewTokenFetcher(endpoint string, opts ...ClientOption) (token.Fetcher, erro
|
||||||
return nil, fmt.Errorf("error parsing expires in: %w", err)
|
return nil, fmt.Errorf("error parsing expires in: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expires := now.Add(time.Duration(expiresSeconds) * time.Second)
|
||||||
|
log.Ctx(ctx).Debug().Time("expires", expires).Msg("fetched new Bearer token")
|
||||||
return &token.Token{
|
return &token.Token{
|
||||||
Bearer: resp.IdToken,
|
Bearer: resp.IdToken,
|
||||||
Expires: now.Add(time.Duration(expiresSeconds) * time.Second),
|
Expires: expires,
|
||||||
}, nil
|
}, nil
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,13 @@ func NewURLCache() *URLCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *URLCache) Delete(key string) {
|
||||||
|
c.mx.Lock()
|
||||||
|
defer c.mx.Unlock()
|
||||||
|
|
||||||
|
delete(c.cache, key)
|
||||||
|
}
|
||||||
|
|
||||||
// Get gets the cache entry for the given key, if it exists and has not expired.
|
// Get gets the cache entry for the given key, if it exists and has not expired.
|
||||||
func (c *URLCache) Get(key string, minTTL time.Duration) (*DownloadCacheEntry, bool) {
|
func (c *URLCache) Get(key string, minTTL time.Duration) (*DownloadCacheEntry, bool) {
|
||||||
c.mx.RLock()
|
c.mx.RLock()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue