mirror of
https://github.com/pomerium/pomerium.git
synced 2025-04-29 18:36:30 +02:00
integration: add single-cluster integration tests (#2516)
* integration: add single-cluster integration tests * remove kind load
This commit is contained in:
parent
f5a558d4a0
commit
48cd10d46b
53 changed files with 7455 additions and 31 deletions
27
.github/workflows/test.yaml
vendored
27
.github/workflows/test.yaml
vendored
|
@ -96,9 +96,12 @@ jobs:
|
||||||
|
|
||||||
integration:
|
integration:
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.17.x]
|
go-version: [1.17.x]
|
||||||
platform: [ubuntu-latest]
|
platform: [ubuntu-latest]
|
||||||
|
deployment: [single]
|
||||||
|
idp: [auth0, azure, github, gitlab, google, oidc, okta, onelogin, ping]
|
||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
|
@ -118,27 +121,21 @@ jobs:
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-go-
|
${{ runner.os }}-go-
|
||||||
- name: install mkcert
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: |
|
|
||||||
#!/bin/bash
|
|
||||||
if [ ! -f mkcert ]; then
|
|
||||||
echo "downloading mkcert"
|
|
||||||
sudo curl -Lo mkcert https://github.com/FiloSottile/mkcert/releases/download/v1.4.1/mkcert-v1.4.1-linux-amd64
|
|
||||||
sudo chmod +x mkcert
|
|
||||||
fi
|
|
||||||
sudo install mkcert /usr/local/bin/
|
|
||||||
- name: Create kind cluster
|
|
||||||
uses: helm/kind-action@v1.2.0
|
|
||||||
with:
|
|
||||||
cluster_name: kind
|
|
||||||
|
|
||||||
- name: build dev docker image
|
- name: build dev docker image
|
||||||
run: |
|
run: |
|
||||||
./scripts/build-dev-docker.bash
|
./scripts/build-dev-docker.bash
|
||||||
|
|
||||||
|
- name: start cluster
|
||||||
|
run: |
|
||||||
|
export POMERIUM_TAG=dev
|
||||||
|
cd ./integration/clusters/${{matrix.idp}}-${{matrix.deployment}}
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
- name: integration tests
|
- name: integration tests
|
||||||
run: go test -v ./integration/...
|
run: |
|
||||||
|
(cd ./integration/clusters/${{matrix.idp}}-${{matrix.deployment}} && docker-compose logs -f &)
|
||||||
|
go test -v ./integration/...
|
||||||
|
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
|
|
|
@ -4,7 +4,7 @@ repos:
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
exclude: "docs/.*"
|
exclude: "(docs/.*|integration/tpl/files/.*)"
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
exclude: "examples/.*"
|
exclude: "examples/.*"
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
|
|
21
go.mod
21
go.mod
|
@ -13,6 +13,7 @@ require (
|
||||||
github.com/cespare/xxhash/v2 v2.1.1
|
github.com/cespare/xxhash/v2 v2.1.1
|
||||||
github.com/client9/misspell v0.3.4
|
github.com/client9/misspell v0.3.4
|
||||||
github.com/coreos/go-oidc/v3 v3.0.0
|
github.com/coreos/go-oidc/v3 v3.0.0
|
||||||
|
github.com/docker/docker v20.10.7+incompatible
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.6.1
|
github.com/envoyproxy/protoc-gen-validate v0.6.1
|
||||||
github.com/fsnotify/fsnotify v1.5.0
|
github.com/fsnotify/fsnotify v1.5.0
|
||||||
|
@ -24,9 +25,11 @@ require (
|
||||||
github.com/golangci/golangci-lint v1.42.0
|
github.com/golangci/golangci-lint v1.42.0
|
||||||
github.com/google/btree v1.0.1
|
github.com/google/btree v1.0.1
|
||||||
github.com/google/go-cmp v0.5.6
|
github.com/google/go-cmp v0.5.6
|
||||||
|
github.com/google/go-jsonnet v0.17.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/handlers v1.5.1
|
github.com/gorilla/handlers v1.5.1
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
|
@ -38,6 +41,7 @@ require (
|
||||||
github.com/open-policy-agent/opa v0.31.0
|
github.com/open-policy-agent/opa v0.31.0
|
||||||
github.com/openzipkin/zipkin-go v0.2.5
|
github.com/openzipkin/zipkin-go v0.2.5
|
||||||
github.com/ory/dockertest/v3 v3.7.0
|
github.com/ory/dockertest/v3 v3.7.0
|
||||||
|
github.com/peterbourgon/ff/v3 v3.1.0
|
||||||
github.com/pomerium/csrf v1.7.0
|
github.com/pomerium/csrf v1.7.0
|
||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.0
|
||||||
github.com/prometheus/client_model v0.2.0
|
github.com/prometheus/client_model v0.2.0
|
||||||
|
@ -68,6 +72,7 @@ require (
|
||||||
google.golang.org/protobuf v1.27.1
|
google.golang.org/protobuf v1.27.1
|
||||||
gopkg.in/auth0.v5 v5.19.2
|
gopkg.in/auth0.v5 v5.19.2
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||||
|
sigs.k8s.io/yaml v1.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -79,7 +84,7 @@ require (
|
||||||
github.com/DataDog/datadog-go v3.5.0+incompatible // indirect
|
github.com/DataDog/datadog-go v3.5.0+incompatible // indirect
|
||||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
|
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
|
||||||
github.com/Masterminds/semver v1.5.0 // indirect
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
github.com/Microsoft/go-winio v0.4.17 // indirect
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||||
github.com/OpenPeeDeeP/depguard v1.0.1 // indirect
|
github.com/OpenPeeDeeP/depguard v1.0.1 // indirect
|
||||||
|
@ -96,13 +101,14 @@ require (
|
||||||
github.com/charithe/durationcheck v0.0.8 // indirect
|
github.com/charithe/durationcheck v0.0.8 // indirect
|
||||||
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect
|
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed // indirect
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed // indirect
|
||||||
github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 // indirect
|
github.com/containerd/containerd v1.5.5 // indirect
|
||||||
|
github.com/containerd/continuity v0.1.0 // indirect
|
||||||
github.com/daixiang0/gci v0.2.9 // indirect
|
github.com/daixiang0/gci v0.2.9 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/denis-tingajkin/go-header v0.4.2 // indirect
|
github.com/denis-tingajkin/go-header v0.4.2 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/docker/cli v20.10.7+incompatible // indirect
|
github.com/docker/cli v20.10.7+incompatible // indirect
|
||||||
github.com/docker/docker v20.10.7+incompatible // indirect
|
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
github.com/esimonov/ifshort v1.0.2 // indirect
|
github.com/esimonov/ifshort v1.0.2 // indirect
|
||||||
|
@ -167,7 +173,7 @@ require (
|
||||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||||
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
|
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
|
||||||
github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 // indirect
|
github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 // indirect
|
||||||
github.com/mgechev/revive v1.1.0 // indirect
|
github.com/mgechev/revive v1.1.0 // indirect
|
||||||
|
@ -176,14 +182,15 @@ require (
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
|
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
|
||||||
github.com/moricho/tparallel v0.2.1 // indirect
|
github.com/moricho/tparallel v0.2.1 // indirect
|
||||||
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/nakabonne/nestif v0.3.0 // indirect
|
github.com/nakabonne/nestif v0.3.0 // indirect
|
||||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
|
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
|
||||||
github.com/nishanths/exhaustive v0.2.3 // indirect
|
github.com/nishanths/exhaustive v0.2.3 // indirect
|
||||||
github.com/nishanths/predeclared v0.2.1 // indirect
|
github.com/nishanths/predeclared v0.2.1 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||||
github.com/opencontainers/runc v1.0.0-rc9 // indirect
|
github.com/opencontainers/runc v1.0.1 // indirect
|
||||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||||
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect
|
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect
|
||||||
github.com/philhofer/fwd v1.0.0 // indirect
|
github.com/philhofer/fwd v1.0.0 // indirect
|
||||||
|
@ -206,7 +213,7 @@ require (
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/ssgreg/nlreturn/v2 v2.1.0 // indirect
|
github.com/ssgreg/nlreturn/v2 v2.1.0 // indirect
|
||||||
github.com/stretchr/objx v0.1.1 // indirect
|
github.com/stretchr/objx v0.2.0 // indirect
|
||||||
github.com/subosito/gotenv v1.2.0 // indirect
|
github.com/subosito/gotenv v1.2.0 // indirect
|
||||||
github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b // indirect
|
github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b // indirect
|
||||||
github.com/tetafro/godot v1.4.8 // indirect
|
github.com/tetafro/godot v1.4.8 // indirect
|
||||||
|
|
78
integration/authorization_test.go
Normal file
78
integration/authorization_test.go
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/integration/flows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAuthorization(t *testing.T) {
|
||||||
|
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
accessType := []string{"direct", "api"}
|
||||||
|
for _, at := range accessType {
|
||||||
|
t.Run(at, func(t *testing.T) {
|
||||||
|
var withAPI, withForwardAuth flows.AuthenticateOption
|
||||||
|
|
||||||
|
if at == "api" {
|
||||||
|
if ClusterType == "traefik" || ClusterType == "nginx" {
|
||||||
|
t.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
withAPI = flows.WithAPI()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ClusterType == "nginx" {
|
||||||
|
withForwardAuth = flows.WithForwardAuth(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("public", func(t *testing.T) {
|
||||||
|
client := getClient()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, res.StatusCode, "unexpected status code, headers=%v", res.Header)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("domains", func(t *testing.T) {
|
||||||
|
t.Run("allowed", func(t *testing.T) {
|
||||||
|
client := getClient()
|
||||||
|
res, err := flows.Authenticate(ctx, client, mustParseURL("https://httpdetails.localhost.pomerium.io/by-domain"),
|
||||||
|
withAPI, withForwardAuth, flows.WithEmail("user1@dogs.test"))
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assert.Equal(t, http.StatusOK, res.StatusCode, "expected OK for dogs.test")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("not allowed", func(t *testing.T) {
|
||||||
|
client := getClient()
|
||||||
|
res, err := flows.Authenticate(ctx, client, mustParseURL("https://httpdetails.localhost.pomerium.io/by-domain"),
|
||||||
|
withAPI, withForwardAuth, flows.WithEmail("user1@cats.test"))
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assertDeniedAccess(t, res, "expected Forbidden for cats.test, but got: %d", res.StatusCode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertDeniedAccess(t *testing.T, res *http.Response, msgAndArgs ...interface{}) bool {
|
||||||
|
return assert.Condition(t, func() bool {
|
||||||
|
return res.StatusCode == http.StatusForbidden || res.StatusCode == http.StatusUnauthorized
|
||||||
|
}, msgAndArgs...)
|
||||||
|
}
|
530
integration/clusters/auth0-single/compose.yml
Normal file
530
integration/clusters/auth0-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
530
integration/clusters/azure-single/compose.yml
Normal file
530
integration/clusters/azure-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
530
integration/clusters/github-single/compose.yml
Normal file
530
integration/clusters/github-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
530
integration/clusters/gitlab-single/compose.yml
Normal file
530
integration/clusters/gitlab-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
530
integration/clusters/google-single/compose.yml
Normal file
530
integration/clusters/google-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
530
integration/clusters/oidc-single/compose.yml
Normal file
530
integration/clusters/oidc-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
530
integration/clusters/okta-single/compose.yml
Normal file
530
integration/clusters/okta-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
530
integration/clusters/onelogin-single/compose.yml
Normal file
530
integration/clusters/onelogin-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
530
integration/clusters/ping-single/compose.yml
Normal file
530
integration/clusters/ping-single/compose.yml
Normal file
File diff suppressed because one or more lines are too long
93
integration/cmd/pomerium-integration-tests/main.go
Normal file
93
integration/cmd/pomerium-integration-tests/main.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/google/go-jsonnet"
|
||||||
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
generateCmd := &ffcli.Command{
|
||||||
|
Name: "generate-configuration",
|
||||||
|
Exec: func(ctx context.Context, args []string) error {
|
||||||
|
return runGenerateConfiguration(ctx)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rootCmd := &ffcli.Command{
|
||||||
|
Subcommands: []*ffcli.Command{generateCmd},
|
||||||
|
Exec: func(ctx context.Context, args []string) error {
|
||||||
|
return flag.ErrHelp
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := rootCmd.ParseAndRun(context.Background(), os.Args[1:])
|
||||||
|
if err != nil && !errors.Is(err, flag.ErrHelp) {
|
||||||
|
log.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGenerateConfiguration(ctx context.Context) error {
|
||||||
|
log.Info().Msg("generating configuration")
|
||||||
|
|
||||||
|
root := filepath.Join(".", "integration")
|
||||||
|
if _, err := os.Stat(root); err != nil {
|
||||||
|
return fmt.Errorf("expected integration subfolder in cwd")
|
||||||
|
}
|
||||||
|
tplRoot := filepath.Join(root, "tpl")
|
||||||
|
|
||||||
|
var allSrcPaths []string
|
||||||
|
err := filepath.WalkDir(tplRoot, func(srcPath string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if d.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
allSrcPaths = append(allSrcPaths, srcPath)
|
||||||
|
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sort.Strings(allSrcPaths)
|
||||||
|
|
||||||
|
vm := jsonnet.MakeVM()
|
||||||
|
vm.Importer(&jsonnet.FileImporter{JPaths: allSrcPaths})
|
||||||
|
for _, srcPath := range allSrcPaths {
|
||||||
|
if filepath.Ext(srcPath) != ".jsonnet" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dstPath := filepath.Join(root, srcPath[len(tplRoot)+1:])
|
||||||
|
dstPath = dstPath[:len(dstPath)-len(filepath.Ext(dstPath))]
|
||||||
|
|
||||||
|
contents, err := vm.EvaluateFile(srcPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error evaluating jsonnet (path=%s): %w", srcPath, err)
|
||||||
|
}
|
||||||
|
asYAML, _ := yaml.JSONToYAML([]byte(contents))
|
||||||
|
|
||||||
|
err = os.MkdirAll(filepath.Dir(dstPath), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating directory (path=%s): %w", dstPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(dstPath, asYAML, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing file (path=%s): %w", dstPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
103
integration/control_plane_test.go
Normal file
103
integration/control_plane_test.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDashboard(t *testing.T) {
|
||||||
|
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
t.Run("user dashboard", func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://authenticate.localhost.pomerium.io/.pomerium/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
body, _ := io.ReadAll(res.Body)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusFound, res.StatusCode, "unexpected status code: %s", body)
|
||||||
|
})
|
||||||
|
t.Run("dashboard strict slash redirect", func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://authenticate.localhost.pomerium.io/.pomerium", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
assert.Equal(t, 3, res.StatusCode/100, "unexpected status code")
|
||||||
|
})
|
||||||
|
t.Run("image asset", func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://authenticate.localhost.pomerium.io/.pomerium/assets/img/pomerium.svg", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, res.StatusCode, "unexpected status code")
|
||||||
|
assert.Equal(t, "image/svg+xml", res.Header.Get("Content-Type"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHealth(t *testing.T) {
|
||||||
|
if ClusterType == "traefik" || ClusterType == "nginx" {
|
||||||
|
t.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
pomeriumRoutes := []string{
|
||||||
|
"https://authenticate.localhost.pomerium.io",
|
||||||
|
"https://httpdetails.localhost.pomerium.io",
|
||||||
|
"https://restricted-httpdetails.localhost.pomerium.io",
|
||||||
|
"https://unknown.localhost.pomerium.io",
|
||||||
|
}
|
||||||
|
endpoints := []string{"healthz", "ping"}
|
||||||
|
|
||||||
|
for _, route := range pomeriumRoutes {
|
||||||
|
route := route
|
||||||
|
for _, endpoint := range endpoints {
|
||||||
|
endpoint := endpoint
|
||||||
|
routeToCheck := fmt.Sprintf("%s/%s", route, endpoint)
|
||||||
|
t.Run(routeToCheck, func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", routeToCheck, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, res.StatusCode, "unexpected status code")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
275
integration/flows/flows.go
Normal file
275
integration/flows/flows.go
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
// Package flows has helper functions for working with pomerium end-user use-case flows.
|
||||||
|
package flows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/integration/forms"
|
||||||
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
|
"github.com/pomerium/pomerium/internal/urlutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
authenticateHostname = "authenticate.localhost.pomerium.io"
|
||||||
|
forwardAuthenticateHostname = "forward-authenticate.localhost.pomerium.io"
|
||||||
|
idpHostname = "mock-idp.localhost.pomerium.io"
|
||||||
|
pomeriumCallbackPath = "/.pomerium/callback/"
|
||||||
|
pomeriumAPIPath = "/.pomerium/api/v1/login"
|
||||||
|
)
|
||||||
|
|
||||||
|
type authenticateConfig struct {
|
||||||
|
email string
|
||||||
|
groups []string
|
||||||
|
tokenExpiration time.Duration
|
||||||
|
apiPath string
|
||||||
|
forwardAuth bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// An AuthenticateOption is an option for authentication.
|
||||||
|
type AuthenticateOption func(cfg *authenticateConfig)
|
||||||
|
|
||||||
|
func getAuthenticateConfig(options ...AuthenticateOption) *authenticateConfig {
|
||||||
|
cfg := &authenticateConfig{
|
||||||
|
tokenExpiration: time.Hour * 24,
|
||||||
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
if option != nil {
|
||||||
|
option(cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithForwardAuth enables/disables forward auth.
|
||||||
|
func WithForwardAuth(fa bool) AuthenticateOption {
|
||||||
|
return func(cfg *authenticateConfig) {
|
||||||
|
cfg.forwardAuth = fa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEmail sets the email to use.
|
||||||
|
func WithEmail(email string) AuthenticateOption {
|
||||||
|
return func(cfg *authenticateConfig) {
|
||||||
|
cfg.email = email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithGroups sets the groups to use.
|
||||||
|
func WithGroups(groups ...string) AuthenticateOption {
|
||||||
|
return func(cfg *authenticateConfig) {
|
||||||
|
cfg.groups = groups
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTokenExpiration sets the token expiration.
|
||||||
|
func WithTokenExpiration(tokenExpiration time.Duration) AuthenticateOption {
|
||||||
|
return func(cfg *authenticateConfig) {
|
||||||
|
cfg.tokenExpiration = tokenExpiration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAPI tells authentication to use API authentication flow.
|
||||||
|
func WithAPI() AuthenticateOption {
|
||||||
|
return func(cfg *authenticateConfig) {
|
||||||
|
cfg.apiPath = pomeriumAPIPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate submits a request to a URL, expects a redirect to authenticate and then openid and logs in.
|
||||||
|
// Finally it expects to redirect back to the original page.
|
||||||
|
func Authenticate(ctx context.Context, client *http.Client, url *url.URL, options ...AuthenticateOption) (*http.Response, error) {
|
||||||
|
cfg := getAuthenticateConfig(options...)
|
||||||
|
originalHostname := url.Hostname()
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Serve a local callback for programmatic redirect flow
|
||||||
|
srv := httptest.NewUnstartedServer(http.RedirectHandler(url.String(), http.StatusFound))
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
if cfg.apiPath != "" {
|
||||||
|
srv.Start()
|
||||||
|
apiLogin := url
|
||||||
|
q := apiLogin.Query()
|
||||||
|
q.Set(urlutil.QueryRedirectURI, srv.URL)
|
||||||
|
apiLogin.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
apiLogin.Path = cfg.apiPath
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", apiLogin.String(), nil)
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bodyBytes, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
url, err = url.Parse(string(bodyBytes))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", url.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res *http.Response
|
||||||
|
|
||||||
|
// (1) redirect to authenticate
|
||||||
|
for req.URL.Hostname() == originalHostname {
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
req, err = requestFromRedirectResponse(ctx, res, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("expected redirect 1 to %s: %w", authenticateHostname, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (2) redirect to idp
|
||||||
|
for req.URL.Hostname() == authenticateHostname || req.URL.Hostname() == forwardAuthenticateHostname {
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
req, err = requestFromRedirectResponse(ctx, res, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("expected redirect 2 to %s: %w", idpHostname, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (3) submit the form
|
||||||
|
for req.URL.Hostname() == idpHostname {
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
fs := forms.Parse(res.Body)
|
||||||
|
if len(fs) > 0 {
|
||||||
|
f := fs[0]
|
||||||
|
f.Inputs["email"] = cfg.email
|
||||||
|
if len(cfg.groups) > 0 {
|
||||||
|
f.Inputs["groups"] = strings.Join(cfg.groups, ",")
|
||||||
|
}
|
||||||
|
f.Inputs["token_expiration"] = strconv.Itoa(int(cfg.tokenExpiration.Seconds()))
|
||||||
|
req, err = f.NewRequestWithContext(ctx, req.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req, err = requestFromRedirectResponse(ctx, res, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("expected redirect 3 to %s: %w", idpHostname, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (4) back to authenticate
|
||||||
|
for req.URL.Hostname() == authenticateHostname {
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
req, err = requestFromRedirectResponse(ctx, res, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("expected redirect 4 to %s: %w", originalHostname, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (5) finally to callback
|
||||||
|
if !cfg.forwardAuth && req.URL.Path != pomeriumCallbackPath {
|
||||||
|
return nil, fmt.Errorf("expected to redirect 5 back to %s, but got %s", pomeriumCallbackPath, req.URL.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.forwardAuth {
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
if res.StatusCode != 302 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
originalURL := req.URL.String()
|
||||||
|
req, err = requestFromRedirectResponse(ctx, res, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("expected redirect to %s: %w", originalHostname, err)
|
||||||
|
}
|
||||||
|
log.Info(ctx).
|
||||||
|
Int("count", i).
|
||||||
|
Str("from", originalURL).
|
||||||
|
Str("to", req.URL.String()).
|
||||||
|
Msg("forward-auth redirect")
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
req, err = requestFromRedirectResponse(ctx, res, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("expected redirect to %s: %w", originalHostname, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Programmatic flow: Follow redirect from local callback
|
||||||
|
if cfg.apiPath != "" {
|
||||||
|
req, err = requestFromRedirectResponse(ctx, res, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("expected redirect to %s: %w", srv.URL, err)
|
||||||
|
}
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req, err = requestFromRedirectResponse(ctx, res, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("expected redirect to %s: %w", originalHostname, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestFromRedirectResponse(ctx context.Context, res *http.Response, req *http.Request) (*http.Request, error) {
|
||||||
|
if res.Header.Get("Location") == "" {
|
||||||
|
return nil, fmt.Errorf("no location header found in response headers")
|
||||||
|
}
|
||||||
|
location, err := url.Parse(res.Header.Get("Location"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing location: %w", err)
|
||||||
|
}
|
||||||
|
location = req.URL.ResolveReference(location)
|
||||||
|
newreq, err := http.NewRequestWithContext(ctx, "GET", location.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newreq, nil
|
||||||
|
}
|
93
integration/forms/forms.go
Normal file
93
integration/forms/forms.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// Package forms has helper functions for working with HTML forms.
|
||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Form represents an HTML form.
|
||||||
|
type Form struct {
|
||||||
|
Action string
|
||||||
|
Method string
|
||||||
|
Inputs map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses all the forms in an HTML document.
|
||||||
|
func Parse(r io.Reader) []Form {
|
||||||
|
root, err := html.Parse(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var forms []Form
|
||||||
|
var currentForm *Form
|
||||||
|
var visit func(*html.Node)
|
||||||
|
visit = func(node *html.Node) {
|
||||||
|
if node.Type == html.ElementNode && node.Data == "form" {
|
||||||
|
currentForm = &Form{Action: "", Method: "GET", Inputs: make(map[string]string)}
|
||||||
|
for _, attr := range node.Attr {
|
||||||
|
switch attr.Key {
|
||||||
|
case "action":
|
||||||
|
currentForm.Action = attr.Val
|
||||||
|
case "method":
|
||||||
|
currentForm.Method = strings.ToUpper(attr.Val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentForm != nil && node.Type == html.ElementNode && node.Data == "input" {
|
||||||
|
var name, value string
|
||||||
|
for _, attr := range node.Attr {
|
||||||
|
switch attr.Key {
|
||||||
|
case "name":
|
||||||
|
name = attr.Val
|
||||||
|
case "value":
|
||||||
|
value = attr.Val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name != "" {
|
||||||
|
currentForm.Inputs[name] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for c := node.FirstChild; c != nil; c = c.NextSibling {
|
||||||
|
visit(c)
|
||||||
|
}
|
||||||
|
if node.Type == html.ElementNode && node.Data == "form" {
|
||||||
|
if currentForm != nil {
|
||||||
|
forms = append(forms, *currentForm)
|
||||||
|
}
|
||||||
|
currentForm = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visit(root)
|
||||||
|
return forms
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRequestWithContext creates a new request from the form details.
|
||||||
|
func (f *Form) NewRequestWithContext(ctx context.Context, baseURL *url.URL) (*http.Request, error) {
|
||||||
|
actionURL, err := url.Parse(f.Action)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
actionURL = baseURL.ResolveReference(actionURL)
|
||||||
|
|
||||||
|
vs := make(url.Values)
|
||||||
|
for k, v := range f.Inputs {
|
||||||
|
vs.Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, f.Method, actionURL.String(), strings.NewReader(vs.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// TODO: handle multipart forms
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
return req, nil
|
||||||
|
}
|
|
@ -1,14 +1,29 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/cookiejar"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
"golang.org/x/net/publicsuffix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var IDP, ClusterType string
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||||
|
|
||||||
|
@ -19,6 +34,139 @@ func TestMain(m *testing.M) {
|
||||||
log.Logger = log.Logger.Level(zerolog.InfoLevel)
|
log.Logger = log.Logger.Level(zerolog.InfoLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger := log.With().Logger()
|
||||||
|
ctx := logger.WithContext(context.Background())
|
||||||
|
|
||||||
|
if err := waitForHealthy(ctx); err != nil {
|
||||||
|
_, _ = fmt.Fprintf(os.Stderr, "services not healthy")
|
||||||
|
os.Exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setIDPAndClusterType(ctx)
|
||||||
|
|
||||||
status := m.Run()
|
status := m.Run()
|
||||||
os.Exit(status)
|
os.Exit(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getClient() *http.Client {
|
||||||
|
jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCAs, err := x509.SystemCertPool()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bs, err := os.ReadFile(filepath.Join(".", "tpl", "files", "ca.pem"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_ = rootCAs.AppendCertsFromPEM(bs)
|
||||||
|
|
||||||
|
return &http.Client{
|
||||||
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
},
|
||||||
|
Transport: &http.Transport{
|
||||||
|
DisableKeepAlives: true,
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
RootCAs: rootCAs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Jar: jar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForHealthy(ctx context.Context) error {
|
||||||
|
client := getClient()
|
||||||
|
check := func(endpoint string) error {
|
||||||
|
reqCtx, clearTimeout := context.WithTimeout(ctx, time.Second)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(reqCtx, "GET", endpoint, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if res.StatusCode/100 != 2 {
|
||||||
|
return fmt.Errorf("%s unavailable: %s", endpoint, res.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Int("status", res.StatusCode).Msgf("%s healthy", endpoint)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker := time.NewTicker(time.Second * 3)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
endpoints := []string{
|
||||||
|
"https://authenticate.localhost.pomerium.io/.well-known/pomerium/jwks.json",
|
||||||
|
"https://mock-idp.localhost.pomerium.io/.well-known/jwks.json",
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
var err error
|
||||||
|
for _, endpoint := range endpoints {
|
||||||
|
err = check(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Ctx(ctx).Info().Err(err).Msg("waiting for healthy")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-ticker.C:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIDPAndClusterType(ctx context.Context) {
|
||||||
|
IDP = "oidc"
|
||||||
|
ClusterType = "single"
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("failed to create docker client")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
containers, err := cli.ContainerList(ctx, types.ContainerListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("failed to retrieve docker containers")
|
||||||
|
}
|
||||||
|
for _, container := range containers {
|
||||||
|
for _, name := range container.Names {
|
||||||
|
parts := regexp.MustCompile(`^/(\w+?)-(\w+?)_pomerium.*$`).FindStringSubmatch(name)
|
||||||
|
if len(parts) == 3 {
|
||||||
|
IDP = parts[1]
|
||||||
|
ClusterType = parts[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Str("idp", IDP).Str("cluster-type", ClusterType).Send()
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustParseURL(str string) *url.URL {
|
||||||
|
u, err := url.Parse(str)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
250
integration/policy_test.go
Normal file
250
integration/policy_test.go
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCORS(t *testing.T) {
|
||||||
|
if ClusterType == "traefik" || ClusterType == "nginx" {
|
||||||
|
t.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
t.Run("enabled", func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "OPTIONS", "https://httpdetails.localhost.pomerium.io/cors-enabled", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Access-Control-Request-Method", "GET")
|
||||||
|
req.Header.Set("Origin", "https://httpdetails.localhost.pomerium.io")
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, res.StatusCode, "unexpected status code")
|
||||||
|
})
|
||||||
|
t.Run("disabled", func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "OPTIONS", "https://httpdetails.localhost.pomerium.io/cors-disabled", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Access-Control-Request-Method", "GET")
|
||||||
|
req.Header.Set("Origin", "https://httpdetails.localhost.pomerium.io")
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
assert.NotEqual(t, http.StatusOK, res.StatusCode, "unexpected status code")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPreserveHostHeader(t *testing.T) {
|
||||||
|
if ClusterType == "traefik" || ClusterType == "nginx" {
|
||||||
|
t.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
t.Run("enabled", func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/preserve-host-header-enabled", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
Headers struct {
|
||||||
|
Host string `json:"host"`
|
||||||
|
} `json:"headers"`
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(res.Body).Decode(&result)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, "httpdetails.localhost.pomerium.io", result.Headers.Host,
|
||||||
|
"destination host should be preserved in %v", result)
|
||||||
|
})
|
||||||
|
t.Run("disabled", func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/preserve-host-header-disabled", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
Headers struct {
|
||||||
|
Host string `json:"host"`
|
||||||
|
} `json:"headers"`
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(res.Body).Decode(&result)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NotEqual(t, "httpdetails.localhost.pomerium.io", result.Headers.Host,
|
||||||
|
"destination host should not be preserved in %v", result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetRequestHeaders(t *testing.T) {
|
||||||
|
if ClusterType == "traefik" || ClusterType == "nginx" {
|
||||||
|
t.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(res.Body).Decode(&result)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, "custom-request-header-value", result.Headers["x-custom-request-header"],
|
||||||
|
"expected custom request header to be sent upstream")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveRequestHeaders(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
req.Header.Add("X-Custom-Request-Header-To-Remove", "foo")
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(res.Body).Decode(&result)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, exist := result.Headers["X-Custom-Request-Header-To-Remove"]
|
||||||
|
assert.False(t, exist, "expected X-Custom-Request-Header-To-Remove not to be present.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWebsocket(t *testing.T) {
|
||||||
|
if ClusterType == "traefik" || ClusterType == "nginx" {
|
||||||
|
t.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
t.Run("disabled", func(t *testing.T) {
|
||||||
|
ws, _, err := (&websocket.Dialer{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
},
|
||||||
|
}).DialContext(ctx, "wss://disabled-ws-echo.localhost.pomerium.io", nil)
|
||||||
|
if !assert.Error(t, err, "expected bad handshake when websocket is not enabled") {
|
||||||
|
ws.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("enabled", func(t *testing.T) {
|
||||||
|
ws, _, err := (&websocket.Dialer{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
},
|
||||||
|
}).DialContext(ctx, "wss://enabled-ws-echo.localhost.pomerium.io", nil)
|
||||||
|
if !assert.NoError(t, err, "expected no error when creating websocket") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer ws.Close()
|
||||||
|
|
||||||
|
msg := "hello world"
|
||||||
|
err = ws.WriteJSON("hello world")
|
||||||
|
assert.NoError(t, err, "expected no error when writing json to websocket")
|
||||||
|
err = ws.ReadJSON(&msg)
|
||||||
|
assert.NoError(t, err, "expected no error when reading json from websocket")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGoogleCloudRun(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||||
|
defer clearTimeout()
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", "https://cloudrun.localhost.pomerium.io/", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := getClient().Do(req)
|
||||||
|
if !assert.NoError(t, err, "unexpected http error") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var result struct {
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
|
}
|
||||||
|
err = json.NewDecoder(res.Body).Decode(&result)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Headers["x-idp"] == "google" {
|
||||||
|
assert.NotEmpty(t, result.Headers["authorization"], "expected authorization header when cloudrun is enabled")
|
||||||
|
}
|
||||||
|
}
|
62
integration/tpl/backends/fortio.libsonnet
Normal file
62
integration/tpl/backends/fortio.libsonnet
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
local utils = import '../utils.libsonnet';
|
||||||
|
|
||||||
|
function() {
|
||||||
|
local name = 'fortio',
|
||||||
|
local image = 'fortio/fortio:1.17.0',
|
||||||
|
|
||||||
|
compose: {
|
||||||
|
services:
|
||||||
|
utils.ComposeService(name, {
|
||||||
|
image: image,
|
||||||
|
depends_on: {
|
||||||
|
[name + '-init']: {
|
||||||
|
condition: 'service_completed_successfully',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
command: [
|
||||||
|
'server',
|
||||||
|
'-cert',
|
||||||
|
'/fortio_config/trusted.pem',
|
||||||
|
'-key',
|
||||||
|
'/fortio_config/trusted-key.pem',
|
||||||
|
],
|
||||||
|
ports: [
|
||||||
|
'8079:8079/tcp',
|
||||||
|
],
|
||||||
|
volumes: [
|
||||||
|
'fortio_config:/fortio_config',
|
||||||
|
],
|
||||||
|
}) +
|
||||||
|
utils.ComposeService(name + '-init', {
|
||||||
|
image: 'busybox:latest',
|
||||||
|
command: [
|
||||||
|
'sh',
|
||||||
|
'-c',
|
||||||
|
|||
|
||||||
|
echo "$$CERT" >/fortio_config/trusted.pem
|
||||||
|
echo "$$KEY" >/fortio_config/trusted-key.pem
|
||||||
|
|||,
|
||||||
|
],
|
||||||
|
environment: {
|
||||||
|
CERT: importstr '../files/trusted.pem',
|
||||||
|
KEY: importstr '../files/trusted-key.pem',
|
||||||
|
},
|
||||||
|
volumes: [
|
||||||
|
'fortio_config:/fortio_config',
|
||||||
|
],
|
||||||
|
}) +
|
||||||
|
utils.ComposeService(name + '-ready', {
|
||||||
|
image: 'jwilder/dockerize:0.6.1',
|
||||||
|
command: [
|
||||||
|
'-wait',
|
||||||
|
'http://' + name + ':8080',
|
||||||
|
'-timeout',
|
||||||
|
'10m',
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
volumes: {
|
||||||
|
fortio_config: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
kubernetes: [],
|
||||||
|
}
|
76
integration/tpl/backends/httpdetails.libsonnet
Normal file
76
integration/tpl/backends/httpdetails.libsonnet
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
local utils = import '../utils.libsonnet';
|
||||||
|
|
||||||
|
local Variations() =
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: 'trusted',
|
||||||
|
cert: importstr '../files/trusted.pem',
|
||||||
|
key: importstr '../files/trusted-key.pem',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'untrusted',
|
||||||
|
cert: importstr '../files/untrusted.pem',
|
||||||
|
key: importstr '../files/untrusted-key.pem',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'wrongly-named',
|
||||||
|
cert: importstr '../files/invalid.pem',
|
||||||
|
key: importstr '../files/invalid-key.pem',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
local Command(variation) =
|
||||||
|
[
|
||||||
|
'sh',
|
||||||
|
'-c',
|
||||||
|
|||
|
||||||
|
cat <<-END_OF_HTTPDETAILS | tee /app/fullchain.pem
|
||||||
|
%s
|
||||||
|
END_OF_HTTPDETAILS
|
||||||
|
cat <<-END_OF_HTTPDETAILS | tee /app/privkey.pem
|
||||||
|
%s
|
||||||
|
END_OF_HTTPDETAILS
|
||||||
|
node ./index.js
|
||||||
|
||| % [variation.cert, variation.key],
|
||||||
|
];
|
||||||
|
|
||||||
|
function() {
|
||||||
|
local suffix = 'httpdetails',
|
||||||
|
local image = 'mendhak/http-https-echo:19',
|
||||||
|
|
||||||
|
compose: {
|
||||||
|
services: std.foldl(
|
||||||
|
function(acc, variation)
|
||||||
|
acc +
|
||||||
|
utils.ComposeService(variation.name + '-' + suffix, {
|
||||||
|
image: image,
|
||||||
|
command: Command(variation),
|
||||||
|
}) +
|
||||||
|
utils.ComposeService(variation.name + '-' + suffix + '-ready', {
|
||||||
|
image: 'jwilder/dockerize:0.6.1',
|
||||||
|
command: [
|
||||||
|
'-wait',
|
||||||
|
'http://' + variation.name + '-' + suffix + ':8080',
|
||||||
|
'-timeout',
|
||||||
|
'10m',
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Variations(),
|
||||||
|
{}
|
||||||
|
),
|
||||||
|
|
||||||
|
},
|
||||||
|
kubernetes: std.foldl(
|
||||||
|
function(acc, variation)
|
||||||
|
acc + [
|
||||||
|
utils.KubernetesDeployment(variation.name + '-' + suffix, image, Command(variation), [
|
||||||
|
{ name: 'http', containerPort: 8080 },
|
||||||
|
{ name: 'https', containerPort: 8443 },
|
||||||
|
]),
|
||||||
|
utils.KubernetesService(variation.name + '-' + suffix, [
|
||||||
|
{ name: 'http', port: 8080, targetPort: 'http' },
|
||||||
|
{ name: 'https', port: 8443, targetPort: 'https' },
|
||||||
|
]),
|
||||||
|
], Variations(), []
|
||||||
|
),
|
||||||
|
}
|
43
integration/tpl/backends/mock-idp.libsonnet
Normal file
43
integration/tpl/backends/mock-idp.libsonnet
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
local utils = import '../utils.libsonnet';
|
||||||
|
|
||||||
|
function(idp) {
|
||||||
|
local name = 'mock-idp',
|
||||||
|
local image = 'pomerium/mock-idps:${MOCK_IDPS_TAG:-master}',
|
||||||
|
local command = [
|
||||||
|
'--provider',
|
||||||
|
idp,
|
||||||
|
'--port',
|
||||||
|
'8024',
|
||||||
|
'--root-url',
|
||||||
|
'https://mock-idp.localhost.pomerium.io/',
|
||||||
|
],
|
||||||
|
|
||||||
|
compose: {
|
||||||
|
services:
|
||||||
|
utils.ComposeService(name, {
|
||||||
|
image: image,
|
||||||
|
command: command,
|
||||||
|
ports: [
|
||||||
|
'8024:8024/tcp',
|
||||||
|
],
|
||||||
|
}) +
|
||||||
|
utils.ComposeService(name + '-ready', {
|
||||||
|
image: 'jwilder/dockerize:0.6.1',
|
||||||
|
command: [
|
||||||
|
'-wait',
|
||||||
|
'http://' + name + ':8024/.well-known/openid-configuration',
|
||||||
|
'-timeout',
|
||||||
|
'10m',
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
volumes: {},
|
||||||
|
},
|
||||||
|
kubernetes: [
|
||||||
|
utils.KubernetesDeployment(name, image, command, [
|
||||||
|
{ name: 'http', containerPort: 8024 },
|
||||||
|
]),
|
||||||
|
utils.KubernetesService(name, [
|
||||||
|
{ name: 'http', port: 8024, targetPort: 'http' },
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
}
|
215
integration/tpl/backends/pomerium.libsonnet
Normal file
215
integration/tpl/backends/pomerium.libsonnet
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
local utils = import '../utils.libsonnet';
|
||||||
|
local Routes = (import './routes.libsonnet').Routes;
|
||||||
|
|
||||||
|
local GoogleCloudServerlessAuthenticationServiceAccount(dns_suffix='') =
|
||||||
|
{
|
||||||
|
type: 'service_account',
|
||||||
|
project_id: 'pomerium-redacted',
|
||||||
|
private_key_id: 'e07f7c93870c7e03f883560ecd8fd0f4d27b0081',
|
||||||
|
private_key: importstr '../files/trusted-key.pem',
|
||||||
|
client_email: 'redacted@pomerium-redacted.iam.gserviceaccount.com',
|
||||||
|
client_id: '101215990458000334387',
|
||||||
|
auth_uri: 'http://mock-idp' + dns_suffix + ':8024',
|
||||||
|
token_uri: 'http://mock-idp' + dns_suffix + ':8024/token',
|
||||||
|
auth_provider_x509_cert_url: 'http://mock-idp' + dns_suffix + ':8024',
|
||||||
|
client_x509_cert_url: 'http://mock-idp' + dns_suffix + ':8024',
|
||||||
|
};
|
||||||
|
|
||||||
|
local KubernetesDeployment(name, image, environment) =
|
||||||
|
{
|
||||||
|
apiVersion: 'apps/v1',
|
||||||
|
kind: 'Deployment',
|
||||||
|
metadata: {
|
||||||
|
namespace: 'default',
|
||||||
|
name: name,
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
replicas: 1,
|
||||||
|
selector: { matchLabels: { app: name } },
|
||||||
|
template: {
|
||||||
|
metadata: {
|
||||||
|
labels: { app: name },
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
containers: [{
|
||||||
|
name: name,
|
||||||
|
image: image,
|
||||||
|
imagePullPolicy: 'IfNotPresent',
|
||||||
|
ports: [
|
||||||
|
{ name: 'http', containerPort: 80 },
|
||||||
|
{ name: 'https', containerPort: 443 },
|
||||||
|
{ name: 'grpc', containerPort: 5443 },
|
||||||
|
],
|
||||||
|
env: [
|
||||||
|
{
|
||||||
|
name: k,
|
||||||
|
value: environment[k],
|
||||||
|
}
|
||||||
|
for k in std.objectFields(environment)
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
local KubernetesService(name) =
|
||||||
|
{
|
||||||
|
apiVersion: 'v1',
|
||||||
|
kind: 'Service',
|
||||||
|
metadata: {
|
||||||
|
namespace: 'default',
|
||||||
|
name: name,
|
||||||
|
labels: { app: name },
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
type: 'NodePort',
|
||||||
|
selector: { app: name },
|
||||||
|
ports: [
|
||||||
|
{ name: 'http', port: 80, targetPort: 'http', nodePort: 80 },
|
||||||
|
{ name: 'https', port: 443, targetPort: 'https', nodePort: 443 },
|
||||||
|
{ name: 'grpc', port: 5443, targetPort: 'grpc', nodePort: 5443 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
local Environment(mode, idp, dns_suffix) =
|
||||||
|
{
|
||||||
|
AUTHENTICATE_SERVICE_URL: 'https://authenticate.localhost.pomerium.io',
|
||||||
|
CERTIFICATE: std.base64(importstr '../files/trusted.pem'),
|
||||||
|
CERTIFICATE_KEY: std.base64(importstr '../files/trusted-key.pem'),
|
||||||
|
CERTIFICATE_AUTHORITY: std.base64(importstr '../files/ca.pem'),
|
||||||
|
COOKIE_SECRET: 'UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=',
|
||||||
|
DATABROKER_STORAGE_TYPE: 'redis',
|
||||||
|
DATABROKER_STORAGE_CONNECTION_STRING: 'redis://redis:6379',
|
||||||
|
ENVOY_ADMIN_ADDRESS: '0.0.0.0:9901',
|
||||||
|
GOOGLE_CLOUD_SERVERLESS_AUTHENTICATION_SERVICE_ACCOUNT: std.base64(std.manifestJsonEx(
|
||||||
|
GoogleCloudServerlessAuthenticationServiceAccount(dns_suffix), ''
|
||||||
|
)),
|
||||||
|
IDP_PROVIDER: idp,
|
||||||
|
IDP_PROVIDER_URL: 'https://mock-idp.localhost.pomerium.io/',
|
||||||
|
IDP_CLIENT_ID: 'CLIENT_ID',
|
||||||
|
IDP_CLIENT_SECRET: 'CLIENT_SECRET',
|
||||||
|
JWT_CLAIMS_HEADERS: 'email,groups,user',
|
||||||
|
LOG_LEVEL: 'info',
|
||||||
|
POLICY: std.base64(std.manifestJsonEx(Routes(mode, idp, dns_suffix), '')),
|
||||||
|
SHARED_SECRET: 'UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=',
|
||||||
|
SIGNING_KEY: std.base64(importstr '../files/signing-key.pem'),
|
||||||
|
SIGNING_KEY_ALGORITHM: 'ES256',
|
||||||
|
} + if mode == 'multi' then {
|
||||||
|
AUTHORIZE_SERVICE_URL: 'https://pomerium-authorize:5443',
|
||||||
|
DATABROKER_SERVICE_URL: 'https://pomerium-databroker:5443',
|
||||||
|
GRPC_ADDRESS: ':5443',
|
||||||
|
GRPC_INSECURE: 'false',
|
||||||
|
OVERRIDE_CERTIFICATE_NAME: '*.localhost.pomerium.io',
|
||||||
|
} else if mode == 'traefik' then {
|
||||||
|
FORWARD_AUTH_URL: 'https://forward-authenticate.localhost.pomerium.io',
|
||||||
|
} else if mode == 'nginx' then {
|
||||||
|
ADDRESS: ':80',
|
||||||
|
INSECURE_SERVER: 'true',
|
||||||
|
FORWARD_AUTH_URL: 'https://forward-authenticate.localhost.pomerium.io',
|
||||||
|
} else {};
|
||||||
|
|
||||||
|
local ComposeService(name, definition, additionalAliases=[]) =
|
||||||
|
utils.ComposeService(name, definition {
|
||||||
|
depends_on: {
|
||||||
|
[name + '-ready']: {
|
||||||
|
condition: 'service_completed_successfully',
|
||||||
|
}
|
||||||
|
for name in [
|
||||||
|
'fortio',
|
||||||
|
'mock-idp',
|
||||||
|
'redis',
|
||||||
|
'trusted-httpdetails',
|
||||||
|
'untrusted-httpdetails',
|
||||||
|
'verify',
|
||||||
|
'websocket-echo',
|
||||||
|
'wrongly-named-httpdetails',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}, additionalAliases);
|
||||||
|
|
||||||
|
function(mode, idp, dns_suffix='') {
|
||||||
|
local name = 'pomerium',
|
||||||
|
local image = 'pomerium/pomerium:${POMERIUM_TAG:-master}',
|
||||||
|
local environment = Environment(mode, idp, dns_suffix),
|
||||||
|
|
||||||
|
compose: {
|
||||||
|
services: if mode == 'multi' then
|
||||||
|
ComposeService(name + '-authorize', {
|
||||||
|
image: image,
|
||||||
|
environment: environment {
|
||||||
|
SERVICES: 'authorize',
|
||||||
|
},
|
||||||
|
ports: [
|
||||||
|
'9904:9901/tcp',
|
||||||
|
'5446:5443/tcp',
|
||||||
|
],
|
||||||
|
}) +
|
||||||
|
ComposeService(name + '-authenticate', {
|
||||||
|
image: image,
|
||||||
|
environment: environment {
|
||||||
|
SERVICES: 'authenticate',
|
||||||
|
},
|
||||||
|
ports: [
|
||||||
|
'9903:9901/tcp',
|
||||||
|
'5445:5443/tcp',
|
||||||
|
],
|
||||||
|
}, ['authenticate.localhost.pomerium.io']) +
|
||||||
|
ComposeService(name + '-databroker', {
|
||||||
|
image: image,
|
||||||
|
environment: environment {
|
||||||
|
SERVICES: 'databroker',
|
||||||
|
},
|
||||||
|
ports: [
|
||||||
|
'9902:9901/tcp',
|
||||||
|
'5444:5443/tcp',
|
||||||
|
],
|
||||||
|
}) +
|
||||||
|
ComposeService(name + '-proxy', {
|
||||||
|
image: image,
|
||||||
|
environment: environment {
|
||||||
|
SERVICES: 'proxy',
|
||||||
|
},
|
||||||
|
ports: [
|
||||||
|
'80:80/tcp',
|
||||||
|
'443:443/tcp',
|
||||||
|
'5443:5443/tcp',
|
||||||
|
'9901:9901/tcp',
|
||||||
|
],
|
||||||
|
}, ['mock-idp.localhost.pomerium.io'])
|
||||||
|
else if mode == 'traefik' || mode == 'nginx' then
|
||||||
|
ComposeService(name, {
|
||||||
|
image: image,
|
||||||
|
environment: environment,
|
||||||
|
}, ['authenticate.localhost.pomerium.io', 'forward-authenticate.localhost.pomerium.io']) +
|
||||||
|
ComposeService(name + '-ready', {
|
||||||
|
image: 'jwilder/dockerize:0.6.1',
|
||||||
|
command: [
|
||||||
|
'-wait',
|
||||||
|
if mode == 'nginx' then
|
||||||
|
'http://' + name + ':80/healthz'
|
||||||
|
else
|
||||||
|
'https://' + name + ':443/healthz',
|
||||||
|
'-timeout',
|
||||||
|
'10m',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
else
|
||||||
|
ComposeService(name, {
|
||||||
|
image: image,
|
||||||
|
environment: environment,
|
||||||
|
ports: [
|
||||||
|
'80:80/tcp',
|
||||||
|
'443:443/tcp',
|
||||||
|
'9901:9901/tcp',
|
||||||
|
],
|
||||||
|
}, ['authenticate.localhost.pomerium.io']),
|
||||||
|
volumes: {},
|
||||||
|
},
|
||||||
|
kubernetes: [
|
||||||
|
KubernetesService(name),
|
||||||
|
KubernetesDeployment(name, image, environment),
|
||||||
|
],
|
||||||
|
}
|
30
integration/tpl/backends/redis.libsonnet
Normal file
30
integration/tpl/backends/redis.libsonnet
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
local utils = import '../utils.libsonnet';
|
||||||
|
|
||||||
|
function() {
|
||||||
|
local name = 'redis',
|
||||||
|
local image = 'redis:6.2.5-alpine',
|
||||||
|
|
||||||
|
compose: {
|
||||||
|
services:
|
||||||
|
utils.ComposeService(name, {
|
||||||
|
image: image,
|
||||||
|
}) +
|
||||||
|
utils.ComposeService(name + '-ready', {
|
||||||
|
image: 'jwilder/dockerize:0.6.1',
|
||||||
|
command: [
|
||||||
|
'-wait',
|
||||||
|
'tcp://' + name + ':6379',
|
||||||
|
'-timeout',
|
||||||
|
'10m',
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
kubernetes: [
|
||||||
|
utils.KubernetesDeployment(name, image, null, [
|
||||||
|
{ name: 'tcp', containerPort: 6379 },
|
||||||
|
]),
|
||||||
|
utils.KubernetesService(name, [
|
||||||
|
{ name: 'tcp', port: 6379, targetPort: 'tcp' },
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
}
|
197
integration/tpl/backends/routes.libsonnet
Normal file
197
integration/tpl/backends/routes.libsonnet
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
local Routes(mode, idp, dns_suffix) =
|
||||||
|
[
|
||||||
|
{
|
||||||
|
from: 'https://mock-idp.localhost.pomerium.io',
|
||||||
|
to: 'http://mock-idp' + dns_suffix + ':8024',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
preserve_host_header: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://envoy.localhost.pomerium.io',
|
||||||
|
to: 'http://localhost:9901',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://verify.localhost.pomerium.io',
|
||||||
|
to: 'http://verify' + dns_suffix + ':80',
|
||||||
|
allow_any_authenticated_user: true,
|
||||||
|
pass_identity_headers: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://websocket-echo.localhost.pomerium.io',
|
||||||
|
to: 'http://websocket-echo' + dns_suffix + ':80',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
allow_websockets: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://fortio-ui.localhost.pomerium.io',
|
||||||
|
to: 'https://fortio' + dns_suffix + ':8080',
|
||||||
|
allow_any_authenticated_user: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://fortio-ping.localhost.pomerium.io',
|
||||||
|
to: 'https://fortio' + dns_suffix + ':8079',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
tls_custom_ca: std.base64(importstr '../files/ca.pem'),
|
||||||
|
tls_server_name: 'fortio-ping.localhost.pomerium.io',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'tcp+https://redis.localhost.pomerium.io:6379',
|
||||||
|
to: 'tcp://redis' + dns_suffix + ':6379',
|
||||||
|
allow_any_authenticated_user: true,
|
||||||
|
},
|
||||||
|
// tls_skip_verify
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'https://trusted-httpdetails' + dns_suffix + ':8443',
|
||||||
|
path: '/tls-skip-verify-enabled',
|
||||||
|
tls_skip_verify: true,
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'https://trusted-httpdetails' + dns_suffix + ':8443',
|
||||||
|
path: '/tls-skip-verify-disabled',
|
||||||
|
tls_skip_verify: false,
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
},
|
||||||
|
// tls_server_name
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'https://wrongly-named-httpdetails' + dns_suffix + ':8443',
|
||||||
|
path: '/tls-server-name-enabled',
|
||||||
|
tls_server_name: 'httpdetails.localhost.notpomerium.io',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'https://wrongly-named-httpdetails' + dns_suffix + ':8443',
|
||||||
|
path: '/tls-server-name-disabled',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
},
|
||||||
|
// tls_custom_certificate_authority
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'https://untrusted-httpdetails' + dns_suffix + ':8443',
|
||||||
|
path: '/tls-custom-ca-enabled',
|
||||||
|
tls_custom_ca: std.base64(importstr '../files/untrusted-ca.pem'),
|
||||||
|
tls_server_name: 'httpdetails.localhost.pomerium.io',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'https://untrusted-httpdetails' + dns_suffix + ':8443',
|
||||||
|
path: '/tls-custom-ca-disabled',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
},
|
||||||
|
// tls_client_cert
|
||||||
|
// {
|
||||||
|
// from: 'http://httpdetails.localhost.pomerium.io',
|
||||||
|
// to: 'https://mtls-http-details' + dns_suffix + ':8443',
|
||||||
|
// path: '/tls-client-cert-enabled',
|
||||||
|
// tls_client_cert: std.base64(tls.trusted.client.cert),
|
||||||
|
// tls_client_key: std.base64(tls.trusted.client.key),
|
||||||
|
// tls_server_name: 'httpdetails.localhost.pomerium.io',
|
||||||
|
// allow_public_unauthenticated_access: true,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// from: 'http://httpdetails.localhost.pomerium.io',
|
||||||
|
// to: 'https://mtls-http-details' + dns_suffix + ':8443',
|
||||||
|
// path: '/tls-client-cert-disabled',
|
||||||
|
// allow_public_unauthenticated_access: true,
|
||||||
|
// },
|
||||||
|
// cors_allow_preflight option
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
prefix: '/cors-enabled',
|
||||||
|
cors_allow_preflight: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
prefix: '/cors-disabled',
|
||||||
|
cors_allow_preflight: false,
|
||||||
|
},
|
||||||
|
// preserve_host_header option
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
prefix: '/preserve-host-header-enabled',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
preserve_host_header: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
prefix: '/preserve-host-header-disabled',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
preserve_host_header: false,
|
||||||
|
},
|
||||||
|
// authorization policy
|
||||||
|
{
|
||||||
|
from: 'https://restricted-httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
allow_any_authenticated_user: true,
|
||||||
|
pass_identity_headers: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
prefix: '/by-domain',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
allowed_domains: ['dogs.test'],
|
||||||
|
pass_identity_headers: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
prefix: '/by-user',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
allowed_users: ['user1@dogs.test'],
|
||||||
|
pass_identity_headers: true,
|
||||||
|
},
|
||||||
|
// catch-all
|
||||||
|
{
|
||||||
|
from: 'https://httpdetails.localhost.pomerium.io',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
pass_identity_headers: true,
|
||||||
|
set_request_headers: {
|
||||||
|
'X-Custom-Request-Header': 'custom-request-header-value',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// websockets
|
||||||
|
{
|
||||||
|
from: 'https://enabled-ws-echo.localhost.pomerium.io',
|
||||||
|
to: 'http://websocket-echo' + dns_suffix + ':80',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
allow_websockets: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 'https://disabled-ws-echo.localhost.pomerium.io',
|
||||||
|
to: 'http://websocket-echo' + dns_suffix + ':80',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
},
|
||||||
|
// cloudrun
|
||||||
|
{
|
||||||
|
from: 'https://cloudrun.localhost.pomerium.io',
|
||||||
|
to: 'http://trusted-httpdetails' + dns_suffix + ':8080',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
pass_identity_headers: true,
|
||||||
|
enable_google_cloud_serverless_authentication: true,
|
||||||
|
set_request_headers: {
|
||||||
|
'x-idp': idp,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
] + if mode == 'multi' then [
|
||||||
|
{
|
||||||
|
from: 'https://authenticate.localhost.pomerium.io',
|
||||||
|
to: 'https://pomerium-authenticate',
|
||||||
|
allow_public_unauthenticated_access: true,
|
||||||
|
host_rewrite: 'authenticate.localhost.pomerium.io',
|
||||||
|
tls_skip_verify: true,
|
||||||
|
},
|
||||||
|
] else [];
|
||||||
|
|
||||||
|
{
|
||||||
|
Routes: Routes,
|
||||||
|
}
|
55
integration/tpl/backends/verify.libsonnet
Normal file
55
integration/tpl/backends/verify.libsonnet
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
local utils = import '../utils.libsonnet';
|
||||||
|
|
||||||
|
function(mode) {
|
||||||
|
local name = 'verify',
|
||||||
|
local image = 'pomerium/verify:${VERIFY_TAG:-latest}',
|
||||||
|
|
||||||
|
compose: {
|
||||||
|
services:
|
||||||
|
utils.ComposeService(name, {
|
||||||
|
image: image,
|
||||||
|
depends_on: {
|
||||||
|
[name + '-init']: {
|
||||||
|
condition: 'service_completed_successfully',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
SSL_CERT_FILE: '/verify_config/ca.pem',
|
||||||
|
},
|
||||||
|
volumes: [
|
||||||
|
'verify_config:/verify_config',
|
||||||
|
],
|
||||||
|
}) +
|
||||||
|
utils.ComposeService(name + '-init', {
|
||||||
|
image: 'busybox:latest',
|
||||||
|
command: [
|
||||||
|
'sh',
|
||||||
|
'-c',
|
||||||
|
"echo '" + (importstr '../files/ca.pem') + "' > /verify_config/ca.pem",
|
||||||
|
],
|
||||||
|
volumes: [
|
||||||
|
'verify_config:/verify_config',
|
||||||
|
],
|
||||||
|
}) +
|
||||||
|
utils.ComposeService(name + '-ready', {
|
||||||
|
image: 'jwilder/dockerize:0.6.1',
|
||||||
|
command: [
|
||||||
|
'-wait',
|
||||||
|
'http://' + name + ':80/',
|
||||||
|
'-timeout',
|
||||||
|
'10m',
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
volumes: {
|
||||||
|
verify_config: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
kubernetes: [
|
||||||
|
utils.KubernetesService(name, [
|
||||||
|
{ name: 'http', port: 80, targetPort: 'http' },
|
||||||
|
]),
|
||||||
|
utils.KubernetesDeployment(name, image, null, [
|
||||||
|
{ name: 'http', containerPort: 80 },
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
}
|
33
integration/tpl/backends/websocket-echo.libsonnet
Normal file
33
integration/tpl/backends/websocket-echo.libsonnet
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
local utils = import '../utils.libsonnet';
|
||||||
|
|
||||||
|
function() {
|
||||||
|
local name = 'websocket-echo',
|
||||||
|
local image = 'pvtmert/websocketd:latest',
|
||||||
|
local command = ['--port', '80', 'tee'],
|
||||||
|
|
||||||
|
compose: {
|
||||||
|
services:
|
||||||
|
utils.ComposeService(name, {
|
||||||
|
image: image,
|
||||||
|
command: command,
|
||||||
|
}) +
|
||||||
|
utils.ComposeService(name + '-ready', {
|
||||||
|
image: 'jwilder/dockerize:0.6.1',
|
||||||
|
command: [
|
||||||
|
'-wait',
|
||||||
|
'tcp://' + name + ':80',
|
||||||
|
'-timeout',
|
||||||
|
'10m',
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
volumes: {},
|
||||||
|
},
|
||||||
|
kubernetes: [
|
||||||
|
utils.KubernetesDeployment(name, image, command, [
|
||||||
|
{ name: 'http', containerPort: 80 },
|
||||||
|
]),
|
||||||
|
utils.KubernetesService(name, [
|
||||||
|
{ name: 'http', port: 80, targetPort: 'http' },
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('auth0')
|
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('azure')
|
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('github')
|
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('gitlab')
|
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('google')
|
1
integration/tpl/clusters/oidc-single/compose.yml.jsonnet
Normal file
1
integration/tpl/clusters/oidc-single/compose.yml.jsonnet
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('oidc')
|
1
integration/tpl/clusters/okta-single/compose.yml.jsonnet
Normal file
1
integration/tpl/clusters/okta-single/compose.yml.jsonnet
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('okta')
|
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('onelogin')
|
1
integration/tpl/clusters/ping-single/compose.yml.jsonnet
Normal file
1
integration/tpl/clusters/ping-single/compose.yml.jsonnet
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(import '../../deployments/single.libsonnet')('ping')
|
16
integration/tpl/deployments/single.libsonnet
Normal file
16
integration/tpl/deployments/single.libsonnet
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
local utils = import '../utils.libsonnet';
|
||||||
|
|
||||||
|
function(idp) utils.Merge([
|
||||||
|
(import '../backends/fortio.libsonnet')().compose,
|
||||||
|
(import '../backends/httpdetails.libsonnet')().compose,
|
||||||
|
(import '../backends/mock-idp.libsonnet')(idp).compose,
|
||||||
|
(import '../backends/pomerium.libsonnet')('single', idp).compose,
|
||||||
|
(import '../backends/redis.libsonnet')().compose,
|
||||||
|
(import '../backends/verify.libsonnet')('single').compose,
|
||||||
|
(import '../backends/websocket-echo.libsonnet')().compose,
|
||||||
|
{
|
||||||
|
networks: {
|
||||||
|
main: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
40
integration/tpl/files/ca-key.pem
Normal file
40
integration/tpl/files/ca-key.pem
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDWysjM+TFVumCn
|
||||||
|
Y4daCDdTJ+zxNqR+UmyUqVsXQBoXQZAZKQGuzsWq4x+SlZAk0mu6J3JWu6jbiWUu
|
||||||
|
pgZqMRfkfnEd48hnVAGJaM5dY5X6iyHwv/oO1e1ZjiZ/fLYweNn2rcS5eljwMNSQ
|
||||||
|
zbFrUH4SoW3B7re0bBdKzDjh3MMsE0eyzsgpiHpdaXJqVeIW1XE+nlcKDx18iUmv
|
||||||
|
XKmjEOV63aIGouCKmWSBix3i7E1brToCRVxHr5V/0E97FqJhHLc4d/CbOPQ4gDw+
|
||||||
|
neGO/wjy2BH5NvSUPTWYaYA7IvYbuRRx2XF8H9SB5cPwgVYJ+o/o5ryis/dDGtaK
|
||||||
|
rr91unbbYnf8QnCxrtkvvek868pJqMuVWnC7VRD+NWJqFZbPda5aO6JaXkFhW55n
|
||||||
|
KO9/UyP+Ifh6HaJaXq0BEUJe7gp6SlT2d1qJCrkYeaZKpEKf2q0I7cHEbRuNwqw6
|
||||||
|
W5frkozAgMYWvefHk2L7aI0zJ7y7bBiA9YRl56pcPuSoyq4ER60CAwEAAQKCAYEA
|
||||||
|
rbQBAALmqvW3BKew5laOp2k6bThLfv0ZYoAzcnIcp4IWDsLi4YPGx5Q2DE137M9e
|
||||||
|
34TXKt1IiYJrmXYa6fYZ5Gd9Azca8rU1KPLhMRVATQYHxLL8ftLyx+H1sFQi4sBZ
|
||||||
|
ROzyky0mj9htj01JlgfabSavpI5xci+YBp1xwvbNv+83pJsltLDyhGiqZuRdmymy
|
||||||
|
E3np2fCvX++G75J4fa9EZkCmr8c43919MmZXHRUM2n8U0pFVN4P/2wWTwW9kkjSt
|
||||||
|
XCcX4hTOT2lYHaDMTCL9R5b4kbgQt8lTvUEov7alLEvSLeTY/GTlb+kTMCxmctOT
|
||||||
|
J6YIBRp6noserU7UV4wOD8/ADxqtLeGMaHbZuKfJ5gDNaEnUj7UWEAdKxvYXlz55
|
||||||
|
3ya9U72Tsxk6b6o2tySrSXD7OIomGqlXlxI9M/12AW3rjJ1cb3GUk5FQnHAATs/i
|
||||||
|
U+CbWhACq/pFaaSKbyrBBUcvTYt3qngTAUbTBoBN/Vzb6E6jjceBCBMK+QxrhroB
|
||||||
|
AoHBAPOt0FhSZlgxG2T39TT0eaRZ1WKQSqzLMxV1v+maTvxgUoSJzqlueytCj9og
|
||||||
|
LITkpUqZTAhZNEyC192rOj39e913xamF7NVHkUQqBYHXjpVw2TWLuGfmV1PplAvs
|
||||||
|
fy6TH0UQqmTddnVVzJMI8KmYWzN4yivIp08aR8VyhYT4swxOLApr1uoz9lFa9Ii0
|
||||||
|
crljcnUZoJZwD0eMzPeRCRR13b/rK8o424zdWqxJiHsFauwdTV9Q+C5q4CjpkmcW
|
||||||
|
UuknMQKBwQDhpw8Fg+aJwPfvDRY3HN54edStmdyQVmcaK95M0ozox7Rk6UezSZZy
|
||||||
|
MjNixppRc2ZpApfFMiaTfTrMygOLbw1T8X+D4AtppPEVQZKWA7iQu4sUiZsHOTew
|
||||||
|
agyDBTOKXcgDWeV588D84qEPB+QWoYopsse0lxBtnMvc3LyW5wjWkZABXuW/Jx2j
|
||||||
|
RVDRHrMyAktKgvKQqaL+2rXHl7mFb/5pEe3RqjwADfQ/Yp7Lv3PxBy9D583PBlIa
|
||||||
|
0JyVSf4KwT0CgcAFszIlbsAAHh3y7a3psDJMOuG37YIhqpsmTFvR3g8s7h/gA802
|
||||||
|
v2PYLjVpN8lyzlpjdVSG+Xc0tvbPs5qoKo7ELnIMNhrFHmhyfL0mPWGTc1FRZFRK
|
||||||
|
8eNnDhatdLnA4CYiGnKx61BDDF+9rL7caLjxakjoX0gynH3DS5t98cdWaVm0YLNl
|
||||||
|
RRPk8Ui5DeeFGKNrw86y1io1VUDSJa1dsigeviSHFW9lSyQ81XeA0S6gGUtfCGjV
|
||||||
|
xSA7NMN879O+qnECgcEAlGcHJQxrKLuFE21a5+IPmdIeAhIHkdGROxAQwhtS2qDE
|
||||||
|
Tf1xz0KdM/s5+kM9KEYp2vP+loz1+9fHPPm6vQ/LByLzRuqo9tCoUN9wJULLNjxx
|
||||||
|
Ko+ZKnYB3v7PvbdE/0HQEgwkNEEP8gCmBbmd0xhoQiY22tji0APnuxhc2y2UjXDr
|
||||||
|
8UrU9BMolcE3dmCnX0NM+vMFzggSj2ONW3e4Zj6SZc2Jx3MaxLpooOseHkeKW8Dq
|
||||||
|
39DqdLXmd4YtBK3F6pLNAoHBAPJnnPMxZZNJhkSELZ6CbSWbcT9FTrdfwTxF+Y4O
|
||||||
|
VvxujzWhPPNrUg10UdqrJdB9cqpN4Hlkc9Xd8/d4G3ph8qrrbZSiD5g2Pn1X0MB+
|
||||||
|
eaC5IvB+wgEBmOeN/UaeR0K8Omfa0H5+0yuFL0lU1htq1pxMkY7o14FvDF68uJf1
|
||||||
|
2GvEJ932BuPdwh+67hA9yj6lQ458xgsme3dE2C36BCwHlb1uGvc75405InRf9mf4
|
||||||
|
JO5gS4pQR3MBP6W0qDfF/mb0NA==
|
||||||
|
-----END PRIVATE KEY-----
|
28
integration/tpl/files/ca.pem
Normal file
28
integration/tpl/files/ca.pem
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE1zCCAz+gAwIBAgIQZ139cd/paPdkS2JyAu7kEDANBgkqhkiG9w0BAQsFADCB
|
||||||
|
gzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSwwKgYDVQQLDCNjYWxl
|
||||||
|
YkBjYWxlYi1wYy1saW51eCAoQ2FsZWIgRG94c2V5KTEzMDEGA1UEAwwqbWtjZXJ0
|
||||||
|
IGNhbGViQGNhbGViLXBjLWxpbnV4IChDYWxlYiBEb3hzZXkpMB4XDTIxMDgxMDE3
|
||||||
|
MzIwOVoXDTMxMDgxMDE3MzIwOVowgYMxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9w
|
||||||
|
bWVudCBDQTEsMCoGA1UECwwjY2FsZWJAY2FsZWItcGMtbGludXggKENhbGViIERv
|
||||||
|
eHNleSkxMzAxBgNVBAMMKm1rY2VydCBjYWxlYkBjYWxlYi1wYy1saW51eCAoQ2Fs
|
||||||
|
ZWIgRG94c2V5KTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBANbKyMz5
|
||||||
|
MVW6YKdjh1oIN1Mn7PE2pH5SbJSpWxdAGhdBkBkpAa7OxarjH5KVkCTSa7oncla7
|
||||||
|
qNuJZS6mBmoxF+R+cR3jyGdUAYlozl1jlfqLIfC/+g7V7VmOJn98tjB42fatxLl6
|
||||||
|
WPAw1JDNsWtQfhKhbcHut7RsF0rMOOHcwywTR7LOyCmIel1pcmpV4hbVcT6eVwoP
|
||||||
|
HXyJSa9cqaMQ5Xrdogai4IqZZIGLHeLsTVutOgJFXEevlX/QT3sWomEctzh38Js4
|
||||||
|
9DiAPD6d4Y7/CPLYEfk29JQ9NZhpgDsi9hu5FHHZcXwf1IHlw/CBVgn6j+jmvKKz
|
||||||
|
90Ma1oquv3W6dttid/xCcLGu2S+96Tzrykmoy5VacLtVEP41YmoVls91rlo7olpe
|
||||||
|
QWFbnmco739TI/4h+HodolperQERQl7uCnpKVPZ3WokKuRh5pkqkQp/arQjtwcRt
|
||||||
|
G43CrDpbl+uSjMCAxha958eTYvtojTMnvLtsGID1hGXnqlw+5KjKrgRHrQIDAQAB
|
||||||
|
o0UwQzAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E
|
||||||
|
FgQUhYZYWIBHyk6ZVTnp3lRt/tyBP00wDQYJKoZIhvcNAQELBQADggGBAA1F/apr
|
||||||
|
l6pNT3Mp/MxhUUgo6usEJCryGQcLRfexyQXGN3huCmIrP55VFa8ETPAtjsr6PMe7
|
||||||
|
7vvEj8eFu2JtKovlQwNewYU9cjAMCVaFiNbrQa20hzhWc2js6dyildE6/DPzbeds
|
||||||
|
KDAxhFNp35SlwtRtKk1SzxJxsqSwjfxI8fp+R/0wO8g0fWTdM2gCpRwYMNwJELEg
|
||||||
|
+dSlvJCwuu+rzxLalzaPF1PMTW72OELal/j5sD+2VytQ4k+HUDbyt2DnQT7YQ3zo
|
||||||
|
q02x2u2sm1WW/o/uh8pjPxkGQqL2mryZs6VH9VCU3QkKNDssNd71lr3wPoE4YRHe
|
||||||
|
UvzD1eDeelzBUFNIpDCjdCsL55yIPqUsr6lmjpBPL0vea33QTMbcsSxu0umGXDbU
|
||||||
|
66juU4Z1jOE0wClIvaO699J+E2gBe1jUN6At6b8BSoZqCqXYoDHGei9RBUdvgqto
|
||||||
|
kVsoJfDI/TFMekYgpL5UVYmLdfgqLPPRP9pQBLDx3mszeAqnvfTICAzfXg==
|
||||||
|
-----END CERTIFICATE-----
|
28
integration/tpl/files/client-key.pem
Normal file
28
integration/tpl/files/client-key.pem
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDeC7rZneOT2JwR
|
||||||
|
pa+PGG7WAigfI/oQCNzzMV12T2cdicHz2e/HioWfWeWy9PlVSosgl4C4jF5pV8hR
|
||||||
|
rkARvlpZklOn6Cl55w1pk0lbVa84AFsIKCrqBJQhtAGx6KxACvrkuWlA5uDTWYn5
|
||||||
|
DvMeYWxExb/VKETaSLvjN2J4N1HlZiSqzA9D+uPM5rqCmj8425EjJGw8xjpv2FS3
|
||||||
|
LW3sjm1V3FbFTrPLj3hYE7f7U+CqNQd3gW6lAG3FaKeh9SlGvmb5rEF3z1iWrcpO
|
||||||
|
DZ8KzbdZgKbFISJgecvPdAHuhFkg3onk3RbYdTZT0fo/R5Aj6FT3/v4DX6Xx7xZY
|
||||||
|
tegm3VkzAgMBAAECggEAfbVoWHGh+P7mBLuns7yiaziXXGHy3YcXB/vHrQZxG3D1
|
||||||
|
REf7Dx4mXjv35iP40Me+EnqTXmfhv4P6Hfwnu6Pn5NQJ1oKCkMg1eLLxEetloq/Y
|
||||||
|
2bpb6VckQhx15TIT6sIMntc1do//csg7a6yCCY4gTKMj4trEeEw7Svz9G5A+Jj9q
|
||||||
|
uAJWbXWpCw97Qu8qrIqmdobb1fbp5/9p54XmcgHAtYfYPcdNGlc4IeDZhMV5Pya7
|
||||||
|
7ULfeIIfAMWKG2iGKQfzGTqk2+2hZnc8y4SQc84hbL3GRphEr5cIz91NTcStRTC1
|
||||||
|
O+5Vzpw7A42ktDW1ZQwLQ6JHDubjXSFyy1bzz/Wn2QKBgQDpgi+yq0u84BJXYOVH
|
||||||
|
zzvKzMQv8aW9ezn6y7te3fbygU3x7F2GvMcpbju2xjSP8GBJTjpyEjqIjzP+fPgo
|
||||||
|
xERVbwrjzmJ1OrOiAkXQ9T3Y7TNzABG8XspEiXy+TpFFaeKy/rU5MTLc8RPGaOlW
|
||||||
|
bi8ePTjhJ7XvAIdrCcd/uibEnwKBgQDzbuXTqoh7i4wHGbbN8oThMJrMOsT4oiv0
|
||||||
|
Z5mtW5PMHSTu9GRt+sco3iYdFb/YCeqGUKQ7Lb5NWY5bmVc2OFh3TdwFC3zROebp
|
||||||
|
jT4Su9rVJpXj/GDXOZUH3u6DoERcvD+VtMcHummard6ROBX5cNOsCmugCL034LV9
|
||||||
|
1XMmgWNu7QKBgQDKSTOU7nvwJZT+CTzXFpnPt9AFUKuqGEREFZY+Or+hmY6yk3b6
|
||||||
|
MDPAmnQ0hEQopa5kEtbi1xPKFXSPdCdu+YfREx819iapM69GG/3rZWisseAuMdMr
|
||||||
|
glprQUfFfT6wCWiQc8L+xrYvXNEqwtvROiarZZIOy136rFSjz5b5+YN4NQKBgQDK
|
||||||
|
axmCYxgwGv5p3RDruVCS69acIfYthLQl+4uG4lJIdKeEZwWnidLXgbmRj8dBPiWc
|
||||||
|
YCvf5Y6LRP+h3STuufWd5skgDMhSNeJzq/XEoB48BWS3+eEQthndPJt6KecOcZ4x
|
||||||
|
vuuM2o37h749ZLSpAQ+Ry+xoWzvz3c8sfjPM/eQPlQKBgHGTKABY8IvQZ+dFY8Kj
|
||||||
|
VdXAfstMx9T/usfZHl/d5/J1brh18Sj+XGT/FMrG1Zk1++ql+IPWwGYaUtNntaQw
|
||||||
|
X4KGlLJUat2+aEYO3IcHrQqpZuq1Oy7peUNrOxCEtFTuWZQT2LLYa6JMOiMG5/Y7
|
||||||
|
WFGqCtnQc9LUg5a1h02k6Eyp
|
||||||
|
-----END PRIVATE KEY-----
|
25
integration/tpl/files/client.pem
Normal file
25
integration/tpl/files/client.pem
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIESzCCArOgAwIBAgIRAOw5c1g686jRWoMVoRgwfHgwDQYJKoZIhvcNAQELBQAw
|
||||||
|
gYMxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEsMCoGA1UECwwjY2Fs
|
||||||
|
ZWJAY2FsZWItcGMtbGludXggKENhbGViIERveHNleSkxMzAxBgNVBAMMKm1rY2Vy
|
||||||
|
dCBjYWxlYkBjYWxlYi1wYy1saW51eCAoQ2FsZWIgRG94c2V5KTAeFw0yMTA4MTEy
|
||||||
|
MTU1NDZaFw0yMzExMTEyMjU1NDZaMFcxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9w
|
||||||
|
bWVudCBjZXJ0aWZpY2F0ZTEsMCoGA1UECwwjY2FsZWJAY2FsZWItcGMtbGludXgg
|
||||||
|
KENhbGViIERveHNleSkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDe
|
||||||
|
C7rZneOT2JwRpa+PGG7WAigfI/oQCNzzMV12T2cdicHz2e/HioWfWeWy9PlVSosg
|
||||||
|
l4C4jF5pV8hRrkARvlpZklOn6Cl55w1pk0lbVa84AFsIKCrqBJQhtAGx6KxACvrk
|
||||||
|
uWlA5uDTWYn5DvMeYWxExb/VKETaSLvjN2J4N1HlZiSqzA9D+uPM5rqCmj8425Ej
|
||||||
|
JGw8xjpv2FS3LW3sjm1V3FbFTrPLj3hYE7f7U+CqNQd3gW6lAG3FaKeh9SlGvmb5
|
||||||
|
rEF3z1iWrcpODZ8KzbdZgKbFISJgecvPdAHuhFkg3onk3RbYdTZT0fo/R5Aj6FT3
|
||||||
|
/v4DX6Xx7xZYtegm3VkzAgMBAAGjZTBjMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
|
||||||
|
FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwHwYDVR0jBBgwFoAUhYZYWIBHyk6ZVTnp
|
||||||
|
3lRt/tyBP00wEQYDVR0RBAowCIIGY2xpZW50MA0GCSqGSIb3DQEBCwUAA4IBgQAi
|
||||||
|
rSAwrwxiYIsAet5GWL+twMP1LiiifNY5REWJ1k/yu6hvG2bvAjSSVwO9pasMnD04
|
||||||
|
kwf5SvPcbWB/5hfwgYLJfDiuoYRptobLVXbvBtgj9EXzveJV6pZr9/oNaPBNArfr
|
||||||
|
a7N+R1IUNwnwJ5rIFdkpvrNjcxPbYV/XYb7LbuVuuQnmggUZDrKRKhoMIsq491tf
|
||||||
|
g6ZO5i4tBqDWUJk7S83AypTOBZNK2ugIQUWwq02gKEtchAACxg0jsuFD/wxtTQS2
|
||||||
|
TDY9pu0m4z01vNzpZy3oPkx48ZN2U9CGXaiEzjEhr87n8gkDBHmntCMJKbIiPmqD
|
||||||
|
YJvJSxQEHyGPuB5FcmC+yIWQ5FhoICynSUQlXn4gCH7EBEflf3TDoYBt0PNoW8Bc
|
||||||
|
xqfpLRltpIDWcOccmjtK+Ucpqgkvy3uAEo7GPfI8Dzv3m4FYG3GctO0RQgeA//VT
|
||||||
|
WsJPFK7HZdMiCJDEzZ0zvPg8O8Dcp17KW0KAn2BO3R7gZDrZ4lSNct3I91n69hI=
|
||||||
|
-----END CERTIFICATE-----
|
28
integration/tpl/files/invalid-key.pem
Normal file
28
integration/tpl/files/invalid-key.pem
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDVDWPhOpNWAYNT
|
||||||
|
QZ4BR5ZU13HqRg/6B49duFcHPY+hkbQPSZdN+GZjCeRVIK8iAkgM3cvyRs40dygZ
|
||||||
|
eogu9LYo6AN/h6cVCF9ENg5jo7/PjK5/6aIf8/Ss22tCuhUL7UHV6ttf6y0+4Nq1
|
||||||
|
hRQcbyIPij89nmO+mT4Fhs9gNSsj2y0gQQWqN2lGhhBnnaCUxh3ElxIYQsCr85Fy
|
||||||
|
W8wWtPxn6mdFHc/iSUh0edeiExWsbPTdfEAj93J5bidXAi27uxTC8X2vHBBIbnZi
|
||||||
|
pb9zmZxBjDjslEnN4vVc9weW5N3nKcu+7QXJdiHFP32YSET2Opu3OIkJji4rpJqx
|
||||||
|
G1Z7MvPzAgMBAAECggEBAM3XhRO7+1QSXCaZdCZ6WuWXzojxrkf8++gpzXPCZ75L
|
||||||
|
vvMyP8xmXc38Za5VyL+MAr7joENxY5NPON/9AgyUBFdbat3RW323vAt0Ssy8Dfti
|
||||||
|
ScpuGWTT2CcWS/iJPwJp9bzPj6qJ1wo0Rzsv23FpcjgfcuB+4pHpDwJZ8IxcclTN
|
||||||
|
jv5XdmanN0Ai2ONDkIHQyvMTsYAX99OK7nXIs3OW7s4wsm8Wg+loCqTvojTzWuwE
|
||||||
|
TZNFonHAZ81jkrYfNjz+sM/tPuOYD+vWQ89+1IeQKFw1U0iBpF1VvhA7UeQZMeI8
|
||||||
|
S1NpDQTQW0kxmUAlLj7ldnIvknT/x0lKzoafVpk47/kCgYEA+SxnMLHe3Wxb4Kkf
|
||||||
|
7Gwktbth/wlWzUWzQ7c0TdhfEDjcRB7SeGIjrL4/HPyXEsCcGIj84TEob1EA0KVP
|
||||||
|
l6Jeqh5t/sr9da+uLFf6H41yZUaTccoyclnjHsqT+WLTtiTKqf7cXACg5NKbJwUT
|
||||||
|
ldCEu+4Ovur+8Ax6s/mGWNEzar0CgYEA2uOmD+SCIhj16P+3GnpZ0UzyDhUKedTy
|
||||||
|
LisZznroF6RI3BHzNT+YotHORDMiJtmX0slFcInAWaB3htLPbHmvredjlsH35eHW
|
||||||
|
B6wkWmbniJEovPysWdg7xjrj8DoL2dcm6liM1KpSo9k6XWJu36//xF4RTnL8JPEH
|
||||||
|
RPuBWmBXHG8CgYBjJy886lr0I61//eztKK+G/bTmRvIapzTJqnqOy54wl1/XX6iD
|
||||||
|
LRJjKCV3RHBdjvXOsZxnhCdB/KrlXBMLFRq0eX1t2Zr4nNsjXDL1IVU3Rdlge4SN
|
||||||
|
ioVdeGFf6Nq0bXmUIg3QMpPT2pbQ9S0w/ZQEMJv/jwW5wk2FlrLGXyElxQKBgQC3
|
||||||
|
skUzITp1Ey2NFM290uB93m1llBLum9+DD3jg6BTPgngC+K17Cpw2SI0qfx8yK3pW
|
||||||
|
08MK5xAeJ6Un6NNa3eSptX7GjpJUwmq0lasMkz/MRMZDlGmwHOBNRC729D/t2bo3
|
||||||
|
AYlvEGG6UBvDM1CJOVMUoT008Rrahczr/4ZXKnLw0QKBgExc+SXb5IRJIMHEQLkg
|
||||||
|
E7va23sR7x4j75mK6HnSwAM3jKx4GDgpkY1EO+rh+99mq/bIouL8ob/PG7A5RtKp
|
||||||
|
+Sgpqk5N6NpSFMaubsu1EQhqT5pmy0dN5KXecR4s1IylPvth/h3tdXPKGcLMD2M2
|
||||||
|
EN59YIA1o4qWjJsfEiuQ6x7M
|
||||||
|
-----END PRIVATE KEY-----
|
26
integration/tpl/files/invalid.pem
Normal file
26
integration/tpl/files/invalid.pem
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEWDCCAsCgAwIBAgIRAK1MkqoHP+DPILewhMcnnu4wDQYJKoZIhvcNAQELBQAw
|
||||||
|
gYMxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEsMCoGA1UECwwjY2Fs
|
||||||
|
ZWJAY2FsZWItcGMtbGludXggKENhbGViIERveHNleSkxMzAxBgNVBAMMKm1rY2Vy
|
||||||
|
dCBjYWxlYkBjYWxlYi1wYy1saW51eCAoQ2FsZWIgRG94c2V5KTAeFw0yMTA4MTEy
|
||||||
|
MTU0MzRaFw0yMzExMTEyMjU0MzRaMFcxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9w
|
||||||
|
bWVudCBjZXJ0aWZpY2F0ZTEsMCoGA1UECwwjY2FsZWJAY2FsZWItcGMtbGludXgg
|
||||||
|
KENhbGViIERveHNleSkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDV
|
||||||
|
DWPhOpNWAYNTQZ4BR5ZU13HqRg/6B49duFcHPY+hkbQPSZdN+GZjCeRVIK8iAkgM
|
||||||
|
3cvyRs40dygZeogu9LYo6AN/h6cVCF9ENg5jo7/PjK5/6aIf8/Ss22tCuhUL7UHV
|
||||||
|
6ttf6y0+4Nq1hRQcbyIPij89nmO+mT4Fhs9gNSsj2y0gQQWqN2lGhhBnnaCUxh3E
|
||||||
|
lxIYQsCr85FyW8wWtPxn6mdFHc/iSUh0edeiExWsbPTdfEAj93J5bidXAi27uxTC
|
||||||
|
8X2vHBBIbnZipb9zmZxBjDjslEnN4vVc9weW5N3nKcu+7QXJdiHFP32YSET2Opu3
|
||||||
|
OIkJji4rpJqxG1Z7MvPzAgMBAAGjcjBwMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE
|
||||||
|
DDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBSFhlhYgEfKTplVOeneVG3+3IE/TTAo
|
||||||
|
BgNVHREEITAfgh1pbnZhbGlkLmxvY2FsaG9zdC5wb21lcml1bS5pbzANBgkqhkiG
|
||||||
|
9w0BAQsFAAOCAYEABsSByXWA7e8hpKWZK4APWzkvDwiTGrDDE7k0hueJksTZ5Nqw
|
||||||
|
fRdGoUpweWIYzAv1etPAr+B2gsZM/jVRidaGDI1tKPytZ3pP6mQ52CVXkeJQytPr
|
||||||
|
rNDnP3Lbpbs8PHoHw3PVxIyRps1ZbZkgbUsXrSvpp/l+ZObbGQjr3Fdx5oXI6a1V
|
||||||
|
NNC39LkPhjTKtcG+H8dO5GRuDb/9PrzrnDwnl6CoORbEjTKRIFuA+vkFBRjyuccr
|
||||||
|
GQiMNmMxy5CMOsK+Od4+8qhv2ZgnREHyBnjFFhgVLFJ2PwUxk3N4GIzCC8tsD+vb
|
||||||
|
+YJgCS7n6JmcB9SFeyRy+qpolnfEaMvRwnJl6Evj17VCBy7x0gEO6B4lILPpziN8
|
||||||
|
VVhSuRsC0V8aXJJx89mwrg9pzN9w771rFVOCrAEdZei34/yfo8VyBbIR1gUxkRNJ
|
||||||
|
crTI9pT0PK+9OWQ57HtnGmFsPtWT8r7P8xukAPy50wSLF3InjEo8VR2df+V7DVVU
|
||||||
|
aTjNbuaG1NLNyWLH
|
||||||
|
-----END CERTIFICATE-----
|
5
integration/tpl/files/signing-key.pem
Normal file
5
integration/tpl/files/signing-key.pem
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIPRGWwLh75nNXnkk37zDfN8onLwfCiaLPTD+nc8Lx5hcoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEkpBkO0TKmh4JdQfLOeeMd53Knga1WdQXr5Fcepk+dLVKdVKxXCGq
|
||||||
|
h1ojuhuW11GIoOzS9GoSKlNVSRFWVEWDvw==
|
||||||
|
-----END EC PRIVATE KEY-----
|
28
integration/tpl/files/trusted-key.pem
Normal file
28
integration/tpl/files/trusted-key.pem
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8HLBAIzXkPeeg
|
||||||
|
ldUfRKK2jQxSVZD5g+qsjAzpmrq/AtmweK1cGcOtZ6eOL+p8brPDyVhDT0QlI/O/
|
||||||
|
EKgCOFFxUDqoR82iY06SacAjHni6+PO9tVRbFV0w14BDAJSpB+VvWyl+FoPDV/vs
|
||||||
|
Z31FtYw+EwqkbDx/kaT9uzf+LJdlkf14nQQj8Eky/8d3mWJbb/9tjObsaQgJ5LLx
|
||||||
|
CYdImkr77X2LMuDw/1tpH642GE25Nrgm6QHlyKSfYXo38v83ebEqbZUDG+ZioArP
|
||||||
|
mqmkawUWw3ekhj80SJg/TK9PRaN/VvcI1PgAd7LZztUReSmTy5hd9r6rOBxpxwnT
|
||||||
|
DvHkBn6vAgMBAAECggEAB28i0AYUNSb1JnWFbKzruUctu3tCNXovJg6K3BiPVMkq
|
||||||
|
DT1XrJIgF5RHHOlr3OsLE6u7Xz2ctdML6PshiKTtIwtGpivgRpCiJEslmr2zi8AW
|
||||||
|
8eJeqRLZEfsSSJOXTG7RdGsn4qHFJ00s2ZTlcIHSPwnFm+XjJi99U8G4XsUoXo0r
|
||||||
|
Gy+0VCuU7M8gICEHHsrQO9XDD3nT2jiu5TjrKwjut3EmoJssI5bqx33+OBu5BpCP
|
||||||
|
CT473D43P9p3qi/XnfvqGSG2Oj4OajV4fr0o9B3KvIxkMem7WlI3jyy1kApyXqVT
|
||||||
|
bLkLFyWBNTWUZ2R/2wxmuoC6mLZw879MLCKMvk1doQKBgQDhmwGafJNymTiEQZRI
|
||||||
|
SsQx4seqfOKfgFC7ohqH9cROOu8IJ1o7q2pM2W4XiV+S3wTdPGmca6IOjX23isVB
|
||||||
|
2uqNi9S4MnI2/d22Gd/BR9rvBw1eGJoKbrWx22fE8QCEWT1AnO+DuD0jC85yRls7
|
||||||
|
axzlaMrxEu3LI9UE7NtrdQiByQKBgQDVdI6ceIVBT6RgvVGt8zkLjPIFjhQEHAIp
|
||||||
|
uhirgqpS6CX9Blyf2+o40zmfj3he5rCcEoB5MseM+DgFbcVh2e/MVnYiNNw6JCDB
|
||||||
|
BQkF408pZpSeKXvL/oyV/kImMTJ/tUDY0EXxMwSPJB0WltbWreVIHopigXRCbaey
|
||||||
|
uBHVBv/4twKBgHwHuePy5SU1s2qSmzD7Wc2LPfYu3nCOHNRrFGb26MuRfuReri7r
|
||||||
|
2G8TgoESFycp0QTIN8+1JM0XYKxNcJD6B8V1wKbbpQsymneI1gjutiB/Igw/PkDK
|
||||||
|
CL4VP4F4da5NWW1yWgNygLoJvZ/5qiKKisJc0GWk4HKz6mLgzOjQ2LJxAoGBALHZ
|
||||||
|
fN2YeYbyYcaM11p1VilulVTVjY3i/FZiDR4SL/IGJWjN/Szg4iXYsKFmu+dulOZl
|
||||||
|
cBALpEKrqpmzXYtrN6bsv18+5eO3qGbK2DrEq3eWVev2KoTMobxz7g++XBIWJmLA
|
||||||
|
Hhaa6IiPkYD5yyVyHKDbeXgb3o9eqCR7w7fYLjy/AoGAI4D+MFkivwUF7hqf5edS
|
||||||
|
KrltwmodHiqXNbVkwbW1AFPJbiYai4YFfK4IAbif/Ymxf9G78aOkr9ZpCIzOkDPZ
|
||||||
|
YpEwQGWsAhElCFvc8E/5dHESSp+tWtP+NluimpFqiDg3/SUnMwO2xH0nhLa0zejh
|
||||||
|
gmLh4w/CcPyb9ZyXceWU/nU=
|
||||||
|
-----END PRIVATE KEY-----
|
26
integration/tpl/files/trusted.pem
Normal file
26
integration/tpl/files/trusted.pem
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEUjCCArqgAwIBAgIRAKNaEqCmmZfhmcYgZy01WCswDQYJKoZIhvcNAQELBQAw
|
||||||
|
gYMxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEsMCoGA1UECwwjY2Fs
|
||||||
|
ZWJAY2FsZWItcGMtbGludXggKENhbGViIERveHNleSkxMzAxBgNVBAMMKm1rY2Vy
|
||||||
|
dCBjYWxlYkBjYWxlYi1wYy1saW51eCAoQ2FsZWIgRG94c2V5KTAeFw0yMTA4MTAx
|
||||||
|
NzMyMTBaFw0yMzExMTAxODMyMTBaMFcxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9w
|
||||||
|
bWVudCBjZXJ0aWZpY2F0ZTEsMCoGA1UECwwjY2FsZWJAY2FsZWItcGMtbGludXgg
|
||||||
|
KENhbGViIERveHNleSkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8
|
||||||
|
HLBAIzXkPeegldUfRKK2jQxSVZD5g+qsjAzpmrq/AtmweK1cGcOtZ6eOL+p8brPD
|
||||||
|
yVhDT0QlI/O/EKgCOFFxUDqoR82iY06SacAjHni6+PO9tVRbFV0w14BDAJSpB+Vv
|
||||||
|
Wyl+FoPDV/vsZ31FtYw+EwqkbDx/kaT9uzf+LJdlkf14nQQj8Eky/8d3mWJbb/9t
|
||||||
|
jObsaQgJ5LLxCYdImkr77X2LMuDw/1tpH642GE25Nrgm6QHlyKSfYXo38v83ebEq
|
||||||
|
bZUDG+ZioArPmqmkawUWw3ekhj80SJg/TK9PRaN/VvcI1PgAd7LZztUReSmTy5hd
|
||||||
|
9r6rOBxpxwnTDvHkBn6vAgMBAAGjbDBqMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE
|
||||||
|
DDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBSFhlhYgEfKTplVOeneVG3+3IE/TTAi
|
||||||
|
BgNVHREEGzAZghcqLmxvY2FsaG9zdC5wb21lcml1bS5pbzANBgkqhkiG9w0BAQsF
|
||||||
|
AAOCAYEAufQAF79s7c1gmZ9CIKBSGkHh+SH01CuKYnnHiMowHsTioFaUAQsd/P4X
|
||||||
|
c2XBqc34eT3mCvpgZjHbjz6JlnTYJxuLvVqnVB3emtWrb1cQvh8BphxspTlS8uiE
|
||||||
|
AEf/ngtpzfA/f4lpGkzrQ0cyPkEJGz511q97itzn9RZZzVTZxNVFSP2vVhNNQVsW
|
||||||
|
OxakcvYRgnz8AOQS3OPHj2FQc3iibshct5leIwYZFcxINGHR6KL6+/LSePNCEMmK
|
||||||
|
qymVPkQGsIcU6GQ9fxaSu4mp+IUALProizEVI8SVk5nOm3HIez+ZfXhzfnGx06SI
|
||||||
|
6NuoQQPqUBeZeXn2YFYhipeRdrQxvA36/YXa/AkXCeU0pXxbtXKcvatfri5KnYJD
|
||||||
|
kH59a+aFkTsl41tfI2cnRYVddqXVl3OzLbcgAFLn1WeC1xx3xRXi7KldokOlvgv+
|
||||||
|
B6naWfCxRlWZ/lsmHae4kc1WH4Kc7nK+ITb40EkjV68/A7krZsN1VcqNtpomYkgE
|
||||||
|
xjUE8XUu
|
||||||
|
-----END CERTIFICATE-----
|
40
integration/tpl/files/untrusted-ca-key.pem
Normal file
40
integration/tpl/files/untrusted-ca-key.pem
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQDWYpVeBSnee2cA
|
||||||
|
BYofSoWxGMyFaMQ0nJkY0UWM9ckyUh7VfgN+/aFSW2ZSmXuv5drcpi20z3elhPTe
|
||||||
|
98bANbj+/bi0015QWnMenK05ZK6qDtFwo/HVC/Ycaruu96+1J2toeWuEtykW3MCp
|
||||||
|
C1pHYS5g9iVDkpdrznvXKlYuSikjrj7K5toiTvum97LxKkuj6DXjapPD5vteSN1d
|
||||||
|
QgO9CS3sqlcwYA6RjUHwY2VEh2adP37BZrZwO+yJq9qF5y5Glgi8lN4cKlIlFUs/
|
||||||
|
xSpQsxNbNQXtN9mk4imYlZGzYYbbm+foBVPPboa5jVwKDpZ65mOs7JGP6yj+7V7U
|
||||||
|
BMFpW+gKmJtgh/kkAx185h93qwLFPc8/T7n++P1bu+fakXPGPE21rDeLPnUmucIZ
|
||||||
|
pJo5NpYVQv4WvTKq/zMR9Sspz2PFJnERTfTvq+F1q3ZNafEziPsB9oeSnjxwmaZO
|
||||||
|
SV0vXq/qeoqx4v6MBzVAY0/8R2LcpJ4ug0OZ3w0b2t6yo86P5Q8CAwEAAQKCAYEA
|
||||||
|
mE0Ey/xjGDkWnT9SNpSckYmKkiQxbybo5GaXQGLEAkmwuf6BwU+xsW5ZLMj4w6dJ
|
||||||
|
aoNr6Q2SdDYWN+hSe+4udIgPFfcrA26eZdrsfN937jwEsj7l6HJM7zcsCkrPuqQ8
|
||||||
|
e8X2ihwMxr8g53a3NgpmBmAXbP/RLrdL5zmea9gnjb+VwFNsF/+Aa8eAii9/+PtY
|
||||||
|
fS0TuJJ5dSvShxQEz+CbjYwd0LIM534wn/Qc1yhRz9hx1jd/2A/aJJu/7GylxWOD
|
||||||
|
mDwFOMcV0rU18r2e3u78GYTNozWCNE05mNhm7j8fYA4XVqR9wURFkBOPRSqg7Bd3
|
||||||
|
kyQmFQYonPW7xEHKOBGR2f3QUhB+ZKsM8ATpfXUmdoeVgx9Po+5FiqQVaNny1OIJ
|
||||||
|
vJeeYU++93ijZqvxvmgVmg97PxeA0CctTp2+ZFwmn1ZNTE7Zon/6lJ7/u999EyuX
|
||||||
|
s3uApNmjpBjA6davvgSIMdbn810f25yn2XVbzDrRJKSUM+Z6twUYZV53rxMWMQBR
|
||||||
|
AoHBAPRxozUFEUdz50dcuJYv2atfXR64T81XXD4i88K4DhEX60xCkTUFgVTgE0Y1
|
||||||
|
ZXgfe0ZNdGDm0zkQJsUcmxvtGCczYnbJZzOVXKfwyO8+z7dKXdXt0BQ7V7JvH50Y
|
||||||
|
KNh2QCtN1I7nZ5og7snDQkjOcrWD/JNNNkrW680O3lXeq4Cs8A6fCT73bX/KE53K
|
||||||
|
MltyxnfMpmGBqx+SwqLelvMY6fD44lhdIlOBi5/ACWCSMh4KnmIBVJTKKaNFdjKI
|
||||||
|
cv5bXQKBwQDghSlkKHuzdkzui8elNk5vfGl/IyUC3Ncx/ViF8kvZyErs4DgTKFT6
|
||||||
|
FmLx6mEboM4PQzofFLYtgmEkqVIo0FswrGS3BYgL5DGI3BSdWLO+Wqk07A3nRvhS
|
||||||
|
LvgM05Gwrin24Udu2ftrXbj6WVGix5en5xgLD0zopxDx5jISUADzH90V1ty6E5UX
|
||||||
|
W5JU1jVmRlWftg7kwfMJocm8PqgT49JSf9ryEV93Y6x5n+oxAAoorjUFmbS0j/Wo
|
||||||
|
VskI8FG/Z1sCgcBDQMyldrp1TTcxlBoZABtEIh2tqQoTtdhkJBuq1BbSryEGvz3S
|
||||||
|
N6yInInRBDnhnc+93OuLCZbNmVsBWkh2m3nMtz987Raew5ZVglLWOBLQG/7LL/3S
|
||||||
|
wyzyo84v24jJXWd0QpqboqEHb84i5rzi6SH4PNMN9+1bE9yWc2PKflPzOCFn9GuH
|
||||||
|
zm1q/j79Z7cJH//oz/5qz1E0g51XUCR5x739lYw4wY8DKJ4wmpY54p81UriWwET0
|
||||||
|
Ftbz29WUO6RfxOUCgcA/GO1C+qWZD9wbBil7YsG0TzCOzF+waEQKBnsEWc27TLDR
|
||||||
|
1UmtCJ6pEfWIqyfTTePbIjeJWJbCP2vxk6xFUBjwmuJLFUDgpqbNIZyhg7Yv/uai
|
||||||
|
utxFbQqIfi6z3BmLn8anXTRoENa5m8NKiCOLLbCPPUDiitBAagM3GExmHRnHOeM2
|
||||||
|
KgYqPSqfP9rmALVNIuMZWV7iJyeYQ2Ggh7NQs6v+B3SOpxc/REHKhIiacLpqKFs6
|
||||||
|
UbIZNIQDZTBmVLOEqRUCgcA8CZ4Q3OyltYcI0WkrJooNv1u9xdhW0Ch+wJ8JjXlw
|
||||||
|
6+BBsXQDci7UWH2sK6YFLCZFoL/K6BFHywi91R6vDGV9cPYL4LY4EEl0HHEuqGp3
|
||||||
|
o80O6s9fTwZYJYhxRBSRpI3f87LWM76CEVCwQl4D59eQXtvVLod5TL+71jMFddhb
|
||||||
|
L9a2u7f4Nz6iPNZyDrqiqzBzaBUpd79Xt1WGfdB0gyjm9YXAHh7UfS80xtGh5DTJ
|
||||||
|
dzutiHsOfQuQZN0aFKkMw18=
|
||||||
|
-----END PRIVATE KEY-----
|
28
integration/tpl/files/untrusted-ca.pem
Normal file
28
integration/tpl/files/untrusted-ca.pem
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE2DCCA0CgAwIBAgIRALd9GaJR92qi7qL1eHGM6K0wDQYJKoZIhvcNAQELBQAw
|
||||||
|
gYMxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEsMCoGA1UECwwjY2Fs
|
||||||
|
ZWJAY2FsZWItcGMtbGludXggKENhbGViIERveHNleSkxMzAxBgNVBAMMKm1rY2Vy
|
||||||
|
dCBjYWxlYkBjYWxlYi1wYy1saW51eCAoQ2FsZWIgRG94c2V5KTAeFw0yMTA4MTEy
|
||||||
|
MTU2MTBaFw0zMTA4MTEyMTU2MTBaMIGDMR4wHAYDVQQKExVta2NlcnQgZGV2ZWxv
|
||||||
|
cG1lbnQgQ0ExLDAqBgNVBAsMI2NhbGViQGNhbGViLXBjLWxpbnV4IChDYWxlYiBE
|
||||||
|
b3hzZXkpMTMwMQYDVQQDDCpta2NlcnQgY2FsZWJAY2FsZWItcGMtbGludXggKENh
|
||||||
|
bGViIERveHNleSkwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDWYpVe
|
||||||
|
BSnee2cABYofSoWxGMyFaMQ0nJkY0UWM9ckyUh7VfgN+/aFSW2ZSmXuv5drcpi20
|
||||||
|
z3elhPTe98bANbj+/bi0015QWnMenK05ZK6qDtFwo/HVC/Ycaruu96+1J2toeWuE
|
||||||
|
tykW3MCpC1pHYS5g9iVDkpdrznvXKlYuSikjrj7K5toiTvum97LxKkuj6DXjapPD
|
||||||
|
5vteSN1dQgO9CS3sqlcwYA6RjUHwY2VEh2adP37BZrZwO+yJq9qF5y5Glgi8lN4c
|
||||||
|
KlIlFUs/xSpQsxNbNQXtN9mk4imYlZGzYYbbm+foBVPPboa5jVwKDpZ65mOs7JGP
|
||||||
|
6yj+7V7UBMFpW+gKmJtgh/kkAx185h93qwLFPc8/T7n++P1bu+fakXPGPE21rDeL
|
||||||
|
PnUmucIZpJo5NpYVQv4WvTKq/zMR9Sspz2PFJnERTfTvq+F1q3ZNafEziPsB9oeS
|
||||||
|
njxwmaZOSV0vXq/qeoqx4v6MBzVAY0/8R2LcpJ4ug0OZ3w0b2t6yo86P5Q8CAwEA
|
||||||
|
AaNFMEMwDgYDVR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0O
|
||||||
|
BBYEFLcY8EoNofMcrrxzyxIn3W6ZOMVXMA0GCSqGSIb3DQEBCwUAA4IBgQCZzDCv
|
||||||
|
KIHX3GvjNSY5w5bOn4E3w7QHP09ABjT/wuT4LDkZHJMmlrLo3s8bcsQ0sMD1Y///
|
||||||
|
s07cp4xYlqD7BA0AcpvYVYq58xKxsoCwVXmG5cEeOoZmWf3qY2mS8eW96vOFrdIb
|
||||||
|
L4OF4xYUOMRqAOGAAr6VlO7gXa406HzrsA1hYZwreXhOTCZZPZOUnAu05SHFdgaM
|
||||||
|
TJNB/o01tpwQlrTxNmfropoOzyuvH0zU2RrMs0+EbOuC4A2cQ83DIFxvq67lyU0A
|
||||||
|
s1Q6tRM0+UDmJOLz3SdgN+D00hcuuj92GV4bH8BfyUv8NCY0vDij0TSjj4c4Qtc7
|
||||||
|
IPLTZ2g545oczhNgAmT7d+B5InyfiSIKemXqes2jpiAfzPNl9BVxsakcs/YzoYs1
|
||||||
|
+qTjAWuaDsKohEnO4BJuzv0xrce40enRgXyGGFvXu2s4FY2vJqTSo6ysDWnhI3LW
|
||||||
|
dcg6O2F4APCGGe7zsuqiqkpcknBabgzEs9foHq2mfo7XiEzedMN8BNqfSbA=
|
||||||
|
-----END CERTIFICATE-----
|
28
integration/tpl/files/untrusted-key.pem
Normal file
28
integration/tpl/files/untrusted-key.pem
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCgVDM59lGzCRjd
|
||||||
|
UQCyzokqC4sEr7Ln2FpXfHjMWPuNK5vQYccTxto3JlAVXl+oOLHGoryKGDOkRV1S
|
||||||
|
Db3zAxYQNDuYUnraiVgLPrM9NFpHSk/IlACQjRlFRYG0Go3PDR2vJX4qTwgrqQtL
|
||||||
|
OJ5tHnqrt6idtvNp1ISYOIscXf/WIAhh+IuOvas4eie7GETX4eqPqpc6AEFuklmo
|
||||||
|
BHBfMCrGg89WBUTWCZYrHE9BYDL0LG/VwLYn2tDKBrS9iZIlTqPwve8VoGIlx4uv
|
||||||
|
HTdzaVStcRKOXCsbSwXRdt0842d4C1nohQkRHqHoBjQzrJiWJzxGmgByfa2rxbNg
|
||||||
|
15PFwF+ZAgMBAAECggEADTzGefunZTPUFLnSZ/D7jDglwz5KdC/9zYleY+jY5B/8
|
||||||
|
nmjkSfK6I6GLLSh8l2QO8YqQLIqxANglS1gNHdpcYPwfC4WL1S1P0qXboKsI5Sfy
|
||||||
|
jGoD3et4caq6ecdTfAvmLobW8uFRmGE9qHlFQ1cn47OnPVZUpKFCTVslyTLNo70h
|
||||||
|
28gx/lnpgkbeWotJ5GygE/H0jKJlG8/V3+Ppfuq6wypA5ELcGUeMAwmCfUNNlDy3
|
||||||
|
BhXSa6STgL26ar70KZIjTp9B97hIfDWObxgjzMX2JoiWXziszvbfaknfBsmfTm45
|
||||||
|
oUZYO0DuvLdLpxic0GZQwZCT6GzuexxJ9zR/pdahrQKBgQDEiwc0e+M1KaOoIIcw
|
||||||
|
V7pxoGjvd+CC5whS00jSf/rXPSPFxat9Ml5serOzLdRLM/NQ5wB9S7TYc6PJi3Mb
|
||||||
|
8pmbGadIXiGIJY8vX79P/velHT4csgULJAKJF9U65knhaidPPPmXloHOhRWrE8Zq
|
||||||
|
mexVgJZrHLI8197qmi+ctT5rEwKBgQDQ1J84AwI1hEsXHxoSetSznt+ae7pSUb/J
|
||||||
|
byqK9KEp0DLyf8GcS7vxyYGQo0mJDlHaJt56LKv+zdX4wGG85ztbOFVPee6XLKSs
|
||||||
|
I+h7rzc2hKrl+SaI91h1234WsTeJvfUSHyBy9vAwLhd0hplNrt7Tql5Z0VTWHmFE
|
||||||
|
2XbEwcTUIwKBgQDBpioHMDmBW/F/6ezJWOa+pco+h+KRl4i/8qVBog9Im1jvt/9r
|
||||||
|
b4FRaOQ9mt4c6qbGA5Sb30fkLKwoHFniI3ntM616xCRNvJQDnVcmPpVJ/jIAm/YU
|
||||||
|
L/q/kNfrHJOWobzxeaaCESz8imv7D5Tj25zb8cJC7xc+k4Nzq09WG83QOQKBgG28
|
||||||
|
LOZ7/j8tA2BlAYhQb1Dr3UgKWEBFoOgyuEJIhh+4vezb4VtGGL7XSnQ8ubmBgtWF
|
||||||
|
s0a0DrVYaGXMgg+H2pL2qS2YPx3FYcrrG5FS40qMsFkkcXFruFpGOp2mBi8lWJBr
|
||||||
|
NtvykwheUAj1ab1+dKz5S5ca/t99G1PYiiaeQ9XNAoGAVXk4HvdUc5q+BNiYvKUS
|
||||||
|
M2/TDU3cYY72mPCEw7G6Kpn6zMaakQcA1+Z8LkYcLaQKRD/66n99WWT+BcY+QXtC
|
||||||
|
0ZPHjeepDL8q+yXRY8zlcgAukg18Ta5yD1J1014y8UIV+HY8ongTni1sI8N+vKd4
|
||||||
|
+TF2C2Cynf5vQr5man7ShPw=
|
||||||
|
-----END PRIVATE KEY-----
|
26
integration/tpl/files/untrusted.pem
Normal file
26
integration/tpl/files/untrusted.pem
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEUjCCArqgAwIBAgIRAKKYU7PSAFxZbhuLUlbv3iAwDQYJKoZIhvcNAQELBQAw
|
||||||
|
gYMxHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEsMCoGA1UECwwjY2Fs
|
||||||
|
ZWJAY2FsZWItcGMtbGludXggKENhbGViIERveHNleSkxMzAxBgNVBAMMKm1rY2Vy
|
||||||
|
dCBjYWxlYkBjYWxlYi1wYy1saW51eCAoQ2FsZWIgRG94c2V5KTAeFw0yMTA4MTEy
|
||||||
|
MTU2MTFaFw0yMzExMTEyMjU2MTFaMFcxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9w
|
||||||
|
bWVudCBjZXJ0aWZpY2F0ZTEsMCoGA1UECwwjY2FsZWJAY2FsZWItcGMtbGludXgg
|
||||||
|
KENhbGViIERveHNleSkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCg
|
||||||
|
VDM59lGzCRjdUQCyzokqC4sEr7Ln2FpXfHjMWPuNK5vQYccTxto3JlAVXl+oOLHG
|
||||||
|
oryKGDOkRV1SDb3zAxYQNDuYUnraiVgLPrM9NFpHSk/IlACQjRlFRYG0Go3PDR2v
|
||||||
|
JX4qTwgrqQtLOJ5tHnqrt6idtvNp1ISYOIscXf/WIAhh+IuOvas4eie7GETX4eqP
|
||||||
|
qpc6AEFuklmoBHBfMCrGg89WBUTWCZYrHE9BYDL0LG/VwLYn2tDKBrS9iZIlTqPw
|
||||||
|
ve8VoGIlx4uvHTdzaVStcRKOXCsbSwXRdt0842d4C1nohQkRHqHoBjQzrJiWJzxG
|
||||||
|
mgByfa2rxbNg15PFwF+ZAgMBAAGjbDBqMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE
|
||||||
|
DDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBS3GPBKDaHzHK68c8sSJ91umTjFVzAi
|
||||||
|
BgNVHREEGzAZghcqLmxvY2FsaG9zdC5wb21lcml1bS5pbzANBgkqhkiG9w0BAQsF
|
||||||
|
AAOCAYEAizMhh+VYIMp07wGn7+rzAE/651yiMC6kZHIOMHilvimyYvCf+Yc0MrcD
|
||||||
|
mVQgqlUpkn/f2SOFsBQonjAACkWlSHah9KStL0iTvOIH+oGLnv3Y9wrKvwJol3KR
|
||||||
|
c/+mO9R9TS71DoX+rTGRY3BNldpMBZF7HsYt/bg0RSpF0zkZarW+PEMmPw6IgIaD
|
||||||
|
RPGpOiQOqIxQn4d6MyiNGS0QmDeGSZvsC07ZcZ+JxsYi4S+yN6GXt11pstiRXjDv
|
||||||
|
zrO3s8TnVsBux7VDdIYfzMxqz+874MbsUUlb4txr3V48UDRLm7VDQ2/F+o0+Y5wt
|
||||||
|
XAnXTn/6GFpjJvPGr0A1QLOvnhR0DZ4Fl97athu44pqeQywDU5LPP3HqrWRXLy3j
|
||||||
|
BPBC4waHayL9Hnh4zQUe/h6hwC5Nxl/gqfB3Aaqr5PWX6rMFss8AYpB81ci+UJdm
|
||||||
|
KSIn/pMoK6TWkCveoQRQOZD8wfwPF4cUUmWcLFwSveZSiniFrAXQqZbO1k6RDhQf
|
||||||
|
havcwKlK
|
||||||
|
-----END CERTIFICATE-----
|
119
integration/tpl/utils.libsonnet
Normal file
119
integration/tpl/utils.libsonnet
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
local MergeArrays(merge, arrays) =
|
||||||
|
std.foldl(function(acc, el) acc + el, arrays, []);
|
||||||
|
|
||||||
|
local MergeObjects(merge, objects) =
|
||||||
|
std.foldl(function(acc, el) {
|
||||||
|
[f]: if std.objectHas(acc, f) && std.objectHas(el, f) then
|
||||||
|
merge([acc[f], el[f]])
|
||||||
|
else if std.objectHas(el, f) then
|
||||||
|
el[f]
|
||||||
|
else
|
||||||
|
acc[f]
|
||||||
|
for f in std.setUnion(
|
||||||
|
std.set(std.objectFields(acc)),
|
||||||
|
std.set(std.objectFields(el))
|
||||||
|
)
|
||||||
|
}, objects, {});
|
||||||
|
|
||||||
|
local Merge(items) =
|
||||||
|
if std.foldl(function(acc, el) acc && std.isArray(el), items, true) then
|
||||||
|
MergeArrays(Merge, items)
|
||||||
|
else if std.foldl(function(acc, el) acc && std.isObject(el), items, true) then
|
||||||
|
MergeObjects(Merge, items)
|
||||||
|
else
|
||||||
|
items[std.length(items) - 1];
|
||||||
|
|
||||||
|
local KubernetesDeployment(name, image, command, ports) =
|
||||||
|
{
|
||||||
|
apiVersion: 'apps/v1',
|
||||||
|
kind: 'Deployment',
|
||||||
|
metadata: {
|
||||||
|
namespace: 'default',
|
||||||
|
name: name,
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
replicas: 1,
|
||||||
|
selector: { matchLabels: { app: name } },
|
||||||
|
template: {
|
||||||
|
metadata: {
|
||||||
|
labels: { app: name },
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
containers: [
|
||||||
|
{
|
||||||
|
name: name,
|
||||||
|
image: image,
|
||||||
|
ports: ports,
|
||||||
|
} + if std.type(command) == 'null' then {} else {
|
||||||
|
args: command,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
local KubernetesService(name, ports) =
|
||||||
|
{
|
||||||
|
apiVersion: 'v1',
|
||||||
|
kind: 'Service',
|
||||||
|
metadata: {
|
||||||
|
namespace: 'default',
|
||||||
|
name: name,
|
||||||
|
labels: { app: name },
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
selector: { app: name },
|
||||||
|
ports: ports,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
local ParseURL(rawURL) =
|
||||||
|
{
|
||||||
|
local splitLeft(str, pat) =
|
||||||
|
local idxs = std.findSubstr(pat, str);
|
||||||
|
if std.length(idxs) == 0 then
|
||||||
|
[str, '']
|
||||||
|
else
|
||||||
|
[std.substr(str, 0, idxs[0]), std.substr(str, idxs[0] + std.length(pat), std.length(str))],
|
||||||
|
|
||||||
|
local splitRight(str, pat) =
|
||||||
|
local idxs = std.findSubstr(pat, str);
|
||||||
|
if std.length(idxs) == 0 then
|
||||||
|
['', str]
|
||||||
|
else
|
||||||
|
[std.substr(str, 0, idxs[0]), std.substr(str, idxs[0] + std.length(pat), std.length(str))],
|
||||||
|
|
||||||
|
local p0 = ['', rawURL],
|
||||||
|
local p1 = splitRight(p0[1], '://'),
|
||||||
|
local p2 = splitRight(p1[1], '@'),
|
||||||
|
local p3 = splitLeft(p2[1], '/'),
|
||||||
|
local p4 = splitLeft(p3[1], '?'),
|
||||||
|
local p5 = splitLeft(p4[1], '#'),
|
||||||
|
|
||||||
|
scheme: p1[0],
|
||||||
|
user: p2[0],
|
||||||
|
host: p3[0],
|
||||||
|
path: if p4[0] == '' then '' else '/' + p4[0],
|
||||||
|
query: p5[0],
|
||||||
|
fragment: p5[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
local ComposeService(name, definition, additionalAliases=[]) =
|
||||||
|
{
|
||||||
|
[name]: definition {
|
||||||
|
networks: {
|
||||||
|
main: {
|
||||||
|
aliases: [name] + additionalAliases,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
ComposeService: ComposeService,
|
||||||
|
Merge: Merge,
|
||||||
|
KubernetesDeployment: KubernetesDeployment,
|
||||||
|
KubernetesService: KubernetesService,
|
||||||
|
ParseURL: ParseURL,
|
||||||
|
}
|
|
@ -24,5 +24,4 @@ ENTRYPOINT [ "/bin/pomerium" ]
|
||||||
CMD ["-config","/pomerium/config.yaml"]
|
CMD ["-config","/pomerium/config.yaml"]
|
||||||
EOF
|
EOF
|
||||||
docker build --tag=pomerium/pomerium:dev .
|
docker build --tag=pomerium/pomerium:dev .
|
||||||
kind load docker-image pomerium/pomerium:dev
|
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Reference in a new issue