mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-20 12:37:16 +02:00
envoy: Initial changes
This commit is contained in:
parent
8f78497e99
commit
99e788a9b4
107 changed files with 2542 additions and 3322 deletions
|
@ -1,3 +0,0 @@
|
|||
module github.com/pomerium/pomerium/integration/backends/httpdetails
|
||||
|
||||
go 1.14
|
29
integration/backends/httpdetails/index.js
Normal file
29
integration/backends/httpdetails/index.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
const http = require("http");
|
||||
|
||||
const requestListener = function (req, res) {
|
||||
const {
|
||||
pathname: path,
|
||||
hostname: host,
|
||||
port: port,
|
||||
search: query,
|
||||
hash: hash,
|
||||
} = new URL(req.url, `http://${req.headers.host}`);
|
||||
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.writeHead(200);
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
headers: req.headers,
|
||||
method: req.method,
|
||||
host: host,
|
||||
port: port,
|
||||
path: path,
|
||||
query: query,
|
||||
hash: hash,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const server = http.createServer(requestListener);
|
||||
console.log("starting http server on :8080");
|
||||
server.listen(8080);
|
|
@ -1,94 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
certFile, keyFile, mutualAuthCAFile, bindAddr string
|
||||
)
|
||||
|
||||
flag.StringVar(&certFile, "cert-file", "", "the tls cert file to use")
|
||||
flag.StringVar(&keyFile, "key-file", "", "the tls key file to use")
|
||||
flag.StringVar(&mutualAuthCAFile, "mutual-auth-ca-file", "", "if set, require a client cert signed via this ca file")
|
||||
flag.StringVar(&bindAddr, "bind-addr", "", "the address to listen on")
|
||||
flag.Parse()
|
||||
|
||||
srv := &http.Server{
|
||||
Handler: http.HandlerFunc(handle),
|
||||
}
|
||||
if mutualAuthCAFile != "" {
|
||||
caCert, err := ioutil.ReadFile(mutualAuthCAFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to read mutual-auth-ca-file: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
srv.TLSConfig = &tls.Config{
|
||||
ClientCAs: caCertPool,
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
}
|
||||
srv.TLSConfig.BuildNameToCertificate()
|
||||
}
|
||||
|
||||
var err error
|
||||
if certFile != "" && keyFile != "" {
|
||||
if bindAddr == "" {
|
||||
bindAddr = ":5443"
|
||||
}
|
||||
srv.Addr = bindAddr
|
||||
fmt.Println("starting server on", bindAddr)
|
||||
err = srv.ListenAndServeTLS(certFile, keyFile)
|
||||
} else {
|
||||
if bindAddr == "" {
|
||||
bindAddr = ":5080"
|
||||
}
|
||||
srv.Addr = bindAddr
|
||||
fmt.Println("starting server on", bindAddr)
|
||||
err = srv.ListenAndServe()
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to listen and serve: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Headers map[string]string `json:"headers"`
|
||||
Method string `json:"method"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
Path string `json:"path"`
|
||||
Query string `json:"query"`
|
||||
RequestURI string `json:"requestURI"`
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
res := &Result{
|
||||
Headers: map[string]string{},
|
||||
Method: r.Method,
|
||||
Host: r.Host,
|
||||
Port: r.URL.Port(),
|
||||
Path: r.URL.Path,
|
||||
Query: r.URL.RawQuery,
|
||||
RequestURI: r.RequestURI,
|
||||
}
|
||||
for k := range r.Header {
|
||||
res.Headers[k] = r.Header.Get(k)
|
||||
}
|
||||
res.Headers["Host"] = r.Host
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
_ = json.NewEncoder(w).Encode(res)
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
module github.com/pomerium/pomerium/integration/backends/ws-echo
|
||||
|
||||
go 1.14
|
||||
|
||||
require github.com/gorilla/websocket v1.4.2
|
|
@ -1,2 +0,0 @@
|
|||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
@ -1,60 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
certFile, keyFile, bindAddr string
|
||||
)
|
||||
|
||||
flag.StringVar(&certFile, "cert-file", "", "the tls cert file to use")
|
||||
flag.StringVar(&keyFile, "key-file", "", "the tls key file to use")
|
||||
flag.StringVar(&bindAddr, "bind-addr", "", "the address to listen on")
|
||||
flag.Parse()
|
||||
|
||||
var err error
|
||||
if certFile != "" && keyFile != "" {
|
||||
if bindAddr == "" {
|
||||
bindAddr = ":5443"
|
||||
}
|
||||
fmt.Println("starting server on", bindAddr)
|
||||
err = http.ListenAndServeTLS(bindAddr, certFile, keyFile, http.HandlerFunc(handle))
|
||||
} else {
|
||||
if bindAddr == "" {
|
||||
bindAddr = ":5080"
|
||||
}
|
||||
fmt.Println("starting server on", bindAddr)
|
||||
err = http.ListenAndServe(bindAddr, http.HandlerFunc(handle))
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to listen and serve: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func handle(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := websocket.Upgrade(w, r, nil, 1024, 1024)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
for {
|
||||
mt, p, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = conn.WriteMessage(mt, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,3 +49,29 @@ func TestDashboard(t *testing.T) {
|
|||
assert.Equal(t, "image/svg+xml", res.Header.Get("Content-Type"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestHealth(t *testing.T) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
for _, endpoint := range []string{"healthz", "ping"} {
|
||||
endpoint := endpoint
|
||||
t.Run(endpoint, func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://restricted-httpdetails.localhost.pomerium.io/"+endpoint, 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")
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,116 +1,69 @@
|
|||
package cluster
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// TLSCerts holds the certificate authority, certificate and certificate key for a TLS connection.
|
||||
type TLSCerts struct {
|
||||
CA []byte
|
||||
Cert []byte
|
||||
Key []byte
|
||||
Client struct {
|
||||
Cert []byte
|
||||
Key []byte
|
||||
}
|
||||
CA string
|
||||
Cert string
|
||||
Key string
|
||||
}
|
||||
|
||||
// TLSCertsBundle holds various TLSCerts.
|
||||
type TLSCertsBundle struct {
|
||||
Trusted TLSCerts
|
||||
WronglyNamed TLSCerts
|
||||
Untrusted TLSCerts
|
||||
}
|
||||
|
||||
func bootstrapCerts(ctx context.Context) (*TLSCertsBundle, error) {
|
||||
wd := filepath.Join(os.TempDir(), "pomerium-integration-tests", "certs")
|
||||
err := os.MkdirAll(wd, 0755)
|
||||
func bootstrapCerts(ctx context.Context) (*TLSCerts, error) {
|
||||
err := run(ctx, "mkcert", withArgs("-install"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating integration tests working directory: %w", err)
|
||||
return nil, fmt.Errorf("error install root certificate: %w", err)
|
||||
}
|
||||
|
||||
var bundle TLSCertsBundle
|
||||
|
||||
var generators = []struct {
|
||||
certs *TLSCerts
|
||||
caroot string
|
||||
install bool
|
||||
name string
|
||||
}{
|
||||
{&bundle.Trusted, filepath.Join(wd, "trusted"), true, "*.localhost.pomerium.io"},
|
||||
{&bundle.WronglyNamed, filepath.Join(wd, "wrongly-named"), true, "*.localhost.notpomerium.io"},
|
||||
{&bundle.Untrusted, filepath.Join(wd, "untrusted"), false, "*.localhost.pomerium.io"},
|
||||
var buf bytes.Buffer
|
||||
err = run(ctx, "mkcert", withArgs("-CAROOT"), withStdout(&buf))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error running mkcert")
|
||||
}
|
||||
|
||||
for _, generator := range generators {
|
||||
err = os.MkdirAll(generator.caroot, 0755)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating integration tests %s working directory: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
|
||||
args := []string{"-install"}
|
||||
env := []string{"CAROOT=" + generator.caroot}
|
||||
if !generator.install {
|
||||
env = append(env, "TRUST_STORES=xxx")
|
||||
}
|
||||
err = run(ctx, "mkcert", withArgs(args...), withEnv(env...))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating %s certificate authority: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
|
||||
fp := filepath.Join(generator.caroot, "rootCA.pem")
|
||||
generator.certs.CA, err = ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s root ca: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
|
||||
env = []string{"CAROOT=" + generator.caroot}
|
||||
err = run(ctx, "mkcert", withArgs(generator.name), withWorkingDir(generator.caroot), withEnv(env...))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating %s certificates: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
err = run(ctx, "mkcert", withArgs("-client", generator.name), withWorkingDir(generator.caroot), withEnv(env...))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating %s client certificates: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
|
||||
fp = filepath.Join(generator.caroot, strings.ReplaceAll(generator.name, "*", "_wildcard")+".pem")
|
||||
generator.certs.Cert, err = ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s certificate: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
|
||||
fp = filepath.Join(generator.caroot, strings.ReplaceAll(generator.name, "*", "_wildcard")+"-client.pem")
|
||||
generator.certs.Client.Cert, err = ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s client certificate: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
|
||||
fp = filepath.Join(generator.caroot, strings.ReplaceAll(generator.name, "*", "_wildcard")+"-key.pem")
|
||||
generator.certs.Key, err = ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s certificate key: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
fp = filepath.Join(generator.caroot, strings.ReplaceAll(generator.name, "*", "_wildcard")+"-client-key.pem")
|
||||
generator.certs.Client.Key, err = ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s client certificate key: %w",
|
||||
filepath.Base(generator.caroot), err)
|
||||
}
|
||||
caPath := strings.TrimSpace(buf.String())
|
||||
ca, err := ioutil.ReadFile(filepath.Join(caPath, "rootCA.pem"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading root ca: %w", err)
|
||||
}
|
||||
|
||||
return &bundle, nil
|
||||
wd := filepath.Join(os.TempDir(), uuid.New().String())
|
||||
err = os.MkdirAll(wd, 0755)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating temporary directory: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(wd)
|
||||
}()
|
||||
|
||||
err = run(ctx, "mkcert", withArgs("*.localhost.pomerium.io"), withWorkingDir(wd))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating certificates: %w", err)
|
||||
}
|
||||
|
||||
cert, err := ioutil.ReadFile(filepath.Join(wd, "_wildcard.localhost.pomerium.io.pem"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading certificate: %w", err)
|
||||
}
|
||||
|
||||
key, err := ioutil.ReadFile(filepath.Join(wd, "_wildcard.localhost.pomerium.io-key.pem"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading certificate key: %w", err)
|
||||
}
|
||||
|
||||
return &TLSCerts{
|
||||
CA: string(ca),
|
||||
Cert: string(cert),
|
||||
Key: string(key),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ import (
|
|||
|
||||
// A Cluster is used to configure a kubernetes cluster.
|
||||
type Cluster struct {
|
||||
Transport *http.Transport
|
||||
workingDir string
|
||||
|
||||
workingDir string
|
||||
certsBundle *TLSCertsBundle
|
||||
transport http.RoundTripper
|
||||
certs *TLSCerts
|
||||
}
|
||||
|
||||
// New creates a new Cluster.
|
||||
|
@ -32,7 +32,7 @@ func (cluster *Cluster) NewHTTPClient() *http.Client {
|
|||
panic(err)
|
||||
}
|
||||
return &http.Client{
|
||||
Transport: &loggingRoundTripper{cluster.Transport},
|
||||
Transport: &loggingRoundTripper{cluster.transport},
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
@ -19,12 +18,6 @@ func withArgs(args ...string) cmdOption {
|
|||
}
|
||||
}
|
||||
|
||||
func withEnv(env ...string) cmdOption {
|
||||
return func(cmd *exec.Cmd) {
|
||||
cmd.Env = append(os.Environ(), env...)
|
||||
}
|
||||
}
|
||||
|
||||
func withStdin(rdr io.Reader) cmdOption {
|
||||
return func(cmd *exec.Cmd) {
|
||||
cmd.Stdin = rdr
|
||||
|
|
|
@ -15,18 +15,17 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/go-jsonnet"
|
||||
"github.com/pomerium/pomerium/integration/internal/httputil"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/pomerium/pomerium/integration/internal/netutil"
|
||||
)
|
||||
|
||||
var requiredDeployments = []string{
|
||||
"ingress-nginx/nginx-ingress-controller",
|
||||
"default/httpdetails",
|
||||
"default/openid",
|
||||
"default/pomerium-authenticate",
|
||||
"default/pomerium-authorize",
|
||||
"default/pomerium-proxy",
|
||||
"ingress-nginx/nginx-ingress-controller",
|
||||
}
|
||||
|
||||
// Setup configures the test cluster so that it is ready for the integration tests.
|
||||
|
@ -36,7 +35,7 @@ func (cluster *Cluster) Setup(ctx context.Context) error {
|
|||
return fmt.Errorf("error running kubectl cluster-info: %w", err)
|
||||
}
|
||||
|
||||
cluster.certsBundle, err = bootstrapCerts(ctx)
|
||||
cluster.certs, err = bootstrapCerts(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -56,14 +55,13 @@ func (cluster *Cluster) Setup(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
cluster.Transport = &http.Transport{
|
||||
DialContext: netutil.NewLocalDialer((&net.Dialer{}), map[string]string{
|
||||
"443": hostport,
|
||||
}).DialContext,
|
||||
cluster.transport = httputil.NewLocalRoundTripper(&http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
}, map[string]string{
|
||||
"443": hostport,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -145,21 +143,9 @@ func (cluster *Cluster) generateManifests() (string, error) {
|
|||
}
|
||||
|
||||
vm := jsonnet.MakeVM()
|
||||
for _, item := range []struct {
|
||||
name string
|
||||
certs *TLSCerts
|
||||
}{
|
||||
{"trusted", &cluster.certsBundle.Trusted},
|
||||
{"wrongly-named", &cluster.certsBundle.WronglyNamed},
|
||||
{"untrusted", &cluster.certsBundle.Untrusted},
|
||||
} {
|
||||
|
||||
vm.ExtVar("tls-"+item.name+"-ca", string(item.certs.CA))
|
||||
vm.ExtVar("tls-"+item.name+"-cert", string(item.certs.Cert))
|
||||
vm.ExtVar("tls-"+item.name+"-key", string(item.certs.Key))
|
||||
vm.ExtVar("tls-"+item.name+"-client-cert", string(item.certs.Client.Cert))
|
||||
vm.ExtVar("tls-"+item.name+"-client-key", string(item.certs.Client.Key))
|
||||
}
|
||||
vm.ExtVar("tls-ca", cluster.certs.CA)
|
||||
vm.ExtVar("tls-cert", cluster.certs.Cert)
|
||||
vm.ExtVar("tls-key", cluster.certs.Key)
|
||||
vm.Importer(&jsonnet.FileImporter{
|
||||
JPaths: []string{filepath.Join(cluster.workingDir, "manifests")},
|
||||
})
|
||||
|
@ -178,7 +164,7 @@ func applyManifests(ctx context.Context, jsonsrc string) error {
|
|||
}
|
||||
|
||||
log.Info().Msg("waiting for deployments to come up")
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, 15*time.Minute)
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, 5*time.Minute)
|
||||
defer clearTimeout()
|
||||
ticker := time.NewTicker(time.Second * 5)
|
||||
defer ticker.Stop()
|
||||
|
|
47
integration/internal/httputil/httputil.go
Normal file
47
integration/internal/httputil/httputil.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Package httputil has helper functions for working with HTTP.
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type localRoundTripper struct {
|
||||
underlying http.RoundTripper
|
||||
portToAddr map[string]string
|
||||
}
|
||||
|
||||
// NewLocalRoundTripper creates a new http.RoundTripper which routes localhost traffic to the remote destinations
|
||||
// defined by `portToAddr`.
|
||||
func NewLocalRoundTripper(underlying http.RoundTripper, portToAddr map[string]string) http.RoundTripper {
|
||||
lrt := &localRoundTripper{underlying: underlying, portToAddr: portToAddr}
|
||||
return lrt
|
||||
}
|
||||
|
||||
func (lrt *localRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = req.Clone(req.Context())
|
||||
req.URL.Host = lrt.remapHost(req.Context(), req.Host)
|
||||
return lrt.underlying.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (lrt *localRoundTripper) remapHost(ctx context.Context, hostport string) string {
|
||||
host, port, err := net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
host = hostport
|
||||
port = "443"
|
||||
}
|
||||
|
||||
dst, ok := lrt.portToAddr[port]
|
||||
if !ok {
|
||||
return hostport
|
||||
}
|
||||
|
||||
ips, err := net.DefaultResolver.LookupIPAddr(ctx, host)
|
||||
if err != nil || len(ips) == 0 || ips[0].String() != "127.0.0.1" {
|
||||
return hostport
|
||||
}
|
||||
|
||||
return dst
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
// Package netutil has helper types for working with network connections.
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Dialer is a type that has a DialContext method for making a network connection.
|
||||
type Dialer = interface {
|
||||
DialContext(ctx context.Context, network, addr string) (net.Conn, error)
|
||||
}
|
||||
|
||||
type localDialer struct {
|
||||
underlying Dialer
|
||||
portToAddr map[string]string
|
||||
}
|
||||
|
||||
// NewLocalDialer creates a new Dialer which routes localhost traffic to the remote destinations
|
||||
// defined by `portToAddr`.
|
||||
func NewLocalDialer(underlying Dialer, portToAddr map[string]string) Dialer {
|
||||
d := &localDialer{underlying: underlying, portToAddr: portToAddr}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *localDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
addr = d.remapHost(ctx, addr)
|
||||
return d.underlying.DialContext(ctx, network, addr)
|
||||
}
|
||||
|
||||
func (d *localDialer) remapHost(ctx context.Context, hostport string) string {
|
||||
host, port, err := net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
host = hostport
|
||||
port = "443"
|
||||
}
|
||||
|
||||
dst, ok := d.portToAddr[port]
|
||||
if !ok {
|
||||
return hostport
|
||||
}
|
||||
|
||||
ips, err := net.DefaultResolver.LookupIPAddr(ctx, host)
|
||||
if err != nil || len(ips) == 0 || ips[0].String() != "127.0.0.1" {
|
||||
return hostport
|
||||
}
|
||||
|
||||
return dst
|
||||
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
local configMap = function(name, data) {
|
||||
apiVersion: 'v1',
|
||||
kind: 'ConfigMap',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
name: name,
|
||||
labels: {
|
||||
app: name,
|
||||
},
|
||||
},
|
||||
data: data,
|
||||
};
|
||||
|
||||
local service = function(name, tlsName, requireMutualAuth) {
|
||||
local fullName = (if tlsName != null then tlsName + '-' else '') +
|
||||
(if requireMutualAuth then 'mtls-' else '') +
|
||||
name,
|
||||
|
||||
apiVersion: 'v1',
|
||||
kind: 'Service',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
name: fullName,
|
||||
labels: { app: fullName },
|
||||
},
|
||||
spec: {
|
||||
selector: { app: fullName },
|
||||
ports: [
|
||||
{
|
||||
name: 'http',
|
||||
port: 80,
|
||||
targetPort: 'http',
|
||||
},
|
||||
{
|
||||
name: 'https',
|
||||
port: 443,
|
||||
targetPort: 'https',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
local deployment = function(name, tlsName, requireMutualAuth) {
|
||||
local fullName = (if tlsName != null then tlsName + '-' else '') +
|
||||
(if requireMutualAuth then 'mtls-' else '') +
|
||||
name,
|
||||
|
||||
apiVersion: 'apps/v1',
|
||||
kind: 'Deployment',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
name: fullName,
|
||||
},
|
||||
spec: {
|
||||
replicas: 1,
|
||||
selector: { matchLabels: { app: fullName } },
|
||||
template: {
|
||||
metadata: {
|
||||
labels: { app: fullName },
|
||||
},
|
||||
spec: {
|
||||
containers: [{
|
||||
name: 'main',
|
||||
image: 'golang:buster',
|
||||
imagePullPolicy: 'IfNotPresent',
|
||||
args: [
|
||||
'bash',
|
||||
'-c',
|
||||
'cd /src && go run . ' +
|
||||
(if tlsName != null then
|
||||
' -cert-file=/certs/tls.crt -key-file=/certs/tls.key'
|
||||
else
|
||||
'') +
|
||||
(if requireMutualAuth then
|
||||
' -mutual-auth-ca-file=/certs/tls-ca.crt'
|
||||
else
|
||||
''),
|
||||
],
|
||||
ports: [
|
||||
{
|
||||
name: 'http',
|
||||
containerPort: 5080,
|
||||
},
|
||||
{
|
||||
name: 'https',
|
||||
containerPort: 5443,
|
||||
},
|
||||
],
|
||||
volumeMounts: [
|
||||
{
|
||||
name: 'src',
|
||||
mountPath: '/src',
|
||||
},
|
||||
{
|
||||
name: 'certs',
|
||||
mountPath: '/certs',
|
||||
},
|
||||
],
|
||||
}],
|
||||
volumes: [
|
||||
{
|
||||
name: 'src',
|
||||
configMap: {
|
||||
name: name,
|
||||
},
|
||||
},
|
||||
] + if tlsName != null then [
|
||||
{
|
||||
name: 'certs',
|
||||
secret: {
|
||||
secretName: 'pomerium-' + tlsName + '-tls',
|
||||
},
|
||||
},
|
||||
] else [
|
||||
{
|
||||
name: 'certs',
|
||||
emptyDir: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local backends = [
|
||||
{ name: 'httpdetails', files: {
|
||||
'main.go': importstr '../../backends/httpdetails/main.go',
|
||||
'go.mod': importstr '../../backends/httpdetails/go.mod',
|
||||
} },
|
||||
{ name: 'ws-echo', files: {
|
||||
'main.go': importstr '../../backends/ws-echo/main.go',
|
||||
'go.mod': importstr '../../backends/ws-echo/go.mod',
|
||||
'go.sum': importstr '../../backends/ws-echo/go.sum',
|
||||
} },
|
||||
];
|
||||
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'List',
|
||||
items: std.flattenArrays(
|
||||
[
|
||||
[
|
||||
configMap(backend.name, backend.files),
|
||||
service(backend.name, null, false),
|
||||
deployment(backend.name, null, false),
|
||||
service(backend.name, 'wrongly-named', false),
|
||||
deployment(backend.name, 'wrongly-named', false),
|
||||
service(backend.name, 'untrusted', false),
|
||||
deployment(backend.name, 'untrusted', false),
|
||||
]
|
||||
for backend in backends
|
||||
] + [
|
||||
[
|
||||
service('httpdetails', 'trusted', true),
|
||||
deployment('httpdetails', 'trusted', true),
|
||||
],
|
||||
],
|
||||
),
|
||||
}
|
79
integration/manifests/lib/httpdetails.libsonnet
Normal file
79
integration/manifests/lib/httpdetails.libsonnet
Normal file
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'List',
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'ConfigMap',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
name: 'httpdetails',
|
||||
labels: {
|
||||
app: 'httpdetails',
|
||||
},
|
||||
},
|
||||
data: {
|
||||
'index.js': importstr '../../backends/httpdetails/index.js',
|
||||
},
|
||||
},
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'Service',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
name: 'httpdetails',
|
||||
labels: { app: 'httpdetails' },
|
||||
},
|
||||
spec: {
|
||||
selector: { app: 'httpdetails' },
|
||||
ports: [{
|
||||
name: 'http',
|
||||
port: 80,
|
||||
targetPort: 'http',
|
||||
}],
|
||||
},
|
||||
},
|
||||
{
|
||||
apiVersion: 'apps/v1',
|
||||
kind: 'Deployment',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
name: 'httpdetails',
|
||||
},
|
||||
spec: {
|
||||
replicas: 1,
|
||||
selector: { matchLabels: { app: 'httpdetails' } },
|
||||
template: {
|
||||
metadata: {
|
||||
labels: { app: 'httpdetails' },
|
||||
},
|
||||
spec: {
|
||||
containers: [{
|
||||
name: 'httpbin',
|
||||
image: 'node:14-stretch-slim',
|
||||
imagePullPolicy: 'IfNotPresent',
|
||||
args: [
|
||||
'node',
|
||||
'/app/index.js',
|
||||
],
|
||||
ports: [{
|
||||
name: 'http',
|
||||
containerPort: 8080,
|
||||
}],
|
||||
volumeMounts: [{
|
||||
name: 'httpdetails',
|
||||
mountPath: '/app',
|
||||
}],
|
||||
}],
|
||||
volumes: [{
|
||||
name: 'httpdetails',
|
||||
configMap: {
|
||||
name: 'httpdetails',
|
||||
},
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
|
@ -1,160 +1,66 @@
|
|||
local tls = import './tls.libsonnet';
|
||||
|
||||
local PomeriumPolicy = function() std.flattenArrays(
|
||||
local PomeriumPolicy = function() std.flattenArrays([
|
||||
[
|
||||
[
|
||||
// tls_skip_verify
|
||||
{
|
||||
from: 'http://httpdetails.localhost.pomerium.io',
|
||||
to: 'https://untrusted-httpdetails.default.svc.cluster.local',
|
||||
path: '/tls-skip-verify-enabled',
|
||||
tls_skip_verify: true,
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
{
|
||||
from: 'http://httpdetails.localhost.pomerium.io',
|
||||
to: 'https://untrusted-httpdetails.default.svc.cluster.local',
|
||||
path: '/tls-skip-verify-disabled',
|
||||
tls_skip_verify: false,
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
// tls_server_name
|
||||
{
|
||||
from: 'http://httpdetails.localhost.pomerium.io',
|
||||
to: 'https://wrongly-named-httpdetails.default.svc.cluster.local',
|
||||
path: '/tls-server-name-enabled',
|
||||
tls_server_name: 'httpdetails.localhost.notpomerium.io',
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
{
|
||||
from: 'http://httpdetails.localhost.pomerium.io',
|
||||
to: 'https://wrongly-named-httpdetails.default.svc.cluster.local',
|
||||
path: '/tls-server-name-disabled',
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
// tls_custom_certificate_authority
|
||||
{
|
||||
from: 'http://httpdetails.localhost.pomerium.io',
|
||||
to: 'https://untrusted-httpdetails.default.svc.cluster.local',
|
||||
path: '/tls-custom-ca-enabled',
|
||||
tls_custom_ca: std.base64(tls.untrusted.ca),
|
||||
tls_server_name: 'httpdetails.localhost.pomerium.io',
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
{
|
||||
from: 'http://httpdetails.localhost.pomerium.io',
|
||||
to: 'https://untrusted-httpdetails.default.svc.cluster.local',
|
||||
path: '/tls-custom-ca-disabled',
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
// tls_client_cert
|
||||
{
|
||||
from: 'http://httpdetails.localhost.pomerium.io',
|
||||
to: 'https://trusted-mtls-httpdetails.default.svc.cluster.local',
|
||||
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://trusted-mtls-httpdetails.default.svc.cluster.local',
|
||||
path: '/tls-client-cert-disabled',
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
],
|
||||
] + [
|
||||
[
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
prefix: '/by-domain',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
allowed_domains: ['dogs.test'],
|
||||
},
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
prefix: '/by-user',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
allowed_users: ['bob@dogs.test'],
|
||||
},
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
prefix: '/by-group',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
allowed_groups: ['admin'],
|
||||
},
|
||||
// cors_allow_preflight option
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
prefix: '/cors-enabled',
|
||||
cors_allow_preflight: true,
|
||||
},
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
prefix: '/cors-disabled',
|
||||
cors_allow_preflight: false,
|
||||
},
|
||||
// preserve_host_header option
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
path: '/preserve-host-header-enabled',
|
||||
allow_public_unauthenticated_access: true,
|
||||
preserve_host_header: true,
|
||||
},
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
path: '/preserve-host-header-disabled',
|
||||
allow_public_unauthenticated_access: true,
|
||||
preserve_host_header: false,
|
||||
},
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
allow_public_unauthenticated_access: true,
|
||||
set_request_headers: {
|
||||
'X-Custom-Request-Header': 'custom-request-header-value',
|
||||
},
|
||||
},
|
||||
]
|
||||
for domain in ['httpdetails', 'fa-httpdetails', 'ws-echo']
|
||||
] + [
|
||||
[
|
||||
{
|
||||
from: 'http://enabled-ws-echo.localhost.pomerium.io',
|
||||
to: 'http://ws-echo.default.svc.cluster.local',
|
||||
allow_public_unauthenticated_access: true,
|
||||
allow_websockets: true,
|
||||
},
|
||||
{
|
||||
from: 'http://disabled-ws-echo.localhost.pomerium.io',
|
||||
to: 'http://ws-echo.default.svc.cluster.local',
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
],
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
prefix: '/by-domain',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
allowed_domains: ['dogs.test'],
|
||||
},
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
prefix: '/by-user',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
allowed_users: ['bob@dogs.test'],
|
||||
},
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
prefix: '/by-group',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
allowed_groups: ['admin'],
|
||||
},
|
||||
{
|
||||
from: 'http://' + domain + '.localhost.pomerium.io',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
allow_public_unauthenticated_access: true,
|
||||
},
|
||||
{
|
||||
from: 'http://restricted-' + domain + '.localhost.pomerium.io',
|
||||
to: 'http://' + domain + '.default.svc.cluster.local',
|
||||
},
|
||||
]
|
||||
);
|
||||
for domain in ['httpdetails', 'fa-httpdetails']
|
||||
]);
|
||||
|
||||
local PomeriumPolicyHash = std.base64(std.md5(std.manifestJsonEx(PomeriumPolicy(), '')));
|
||||
|
||||
local PomeriumTLSSecret = function(name) {
|
||||
local PomeriumTLSSecret = function() {
|
||||
apiVersion: 'v1',
|
||||
kind: 'Secret',
|
||||
type: 'kubernetes.io/tls',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
name: 'pomerium-' + name + '-tls',
|
||||
name: 'pomerium-tls',
|
||||
},
|
||||
data: {
|
||||
'tls-ca.crt': std.base64(tls[name].ca),
|
||||
'tls.crt': std.base64(tls[name].cert),
|
||||
'tls.key': std.base64(tls[name].key),
|
||||
'tls-client.crt': std.base64(tls[name].client.cert),
|
||||
'tls-client.key': std.base64(tls[name].client.key),
|
||||
'tls.crt': std.base64(tls.cert),
|
||||
'tls.key': std.base64(tls.key),
|
||||
},
|
||||
};
|
||||
|
||||
local PomeriumCAsConfigMap = function() {
|
||||
apiVersion: 'v1',
|
||||
kind: 'ConfigMap',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
name: 'pomerium-cas',
|
||||
labels: {
|
||||
'app.kubernetes.io/part-of': 'pomerium',
|
||||
},
|
||||
},
|
||||
data: {
|
||||
'pomerium.crt': tls.ca,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -184,8 +90,8 @@ local PomeriumConfigMap = function() {
|
|||
SHARED_SECRET: 'Wy+c0uSuIM0yGGXs82MBwTZwRiZ7Ki2T0LANnmzUtkI=',
|
||||
COOKIE_SECRET: 'eZ91a/j9fhgki9zPDU5zHdQWX4io89pJanChMVa5OoM=',
|
||||
|
||||
CERTIFICATE: std.base64(tls.trusted.cert),
|
||||
CERTIFICATE_KEY: std.base64(tls.trusted.key),
|
||||
CERTIFICATE: std.base64(tls.cert),
|
||||
CERTIFICATE_KEY: std.base64(tls.key),
|
||||
|
||||
IDP_PROVIDER: 'oidc',
|
||||
IDP_PROVIDER_URL: 'https://openid.localhost.pomerium.io',
|
||||
|
@ -231,43 +137,25 @@ local PomeriumDeployment = function(svc) {
|
|||
'openid.localhost.pomerium.io',
|
||||
],
|
||||
}],
|
||||
initContainers: [
|
||||
{
|
||||
name: 'init',
|
||||
image: 'buildpack-deps:buster-curl',
|
||||
imagePullPolicy: 'IfNotPresent',
|
||||
command: ['sh', '-c', |||
|
||||
cp /incoming-certs/trusted/tls-ca.crt /usr/local/share/ca-certificates/pomerium-trusted.crt
|
||||
cp /incoming-certs/wrongly-named/tls-ca.crt /usr/local/share/ca-certificates/pomerium-wrongly-named.crt
|
||||
update-ca-certificates
|
||||
|||],
|
||||
volumeMounts: [
|
||||
{
|
||||
name: 'trusted-incoming-certs',
|
||||
mountPath: '/incoming-certs/trusted',
|
||||
},
|
||||
{
|
||||
name: 'wrongly-named-incoming-certs',
|
||||
mountPath: '/incoming-certs/wrongly-named',
|
||||
},
|
||||
{
|
||||
name: 'outgoing-certs',
|
||||
mountPath: '/etc/ssl/certs',
|
||||
},
|
||||
],
|
||||
},
|
||||
] + if svc == 'authenticate' then [
|
||||
{
|
||||
name: 'wait-for-openid',
|
||||
image: 'buildpack-deps:buster-curl',
|
||||
imagePullPolicy: 'IfNotPresent',
|
||||
command: ['sh', '-c', |||
|
||||
while ! curl http://openid.default.svc.cluster.local/.well-known/openid-configuration ; do
|
||||
sleep 5
|
||||
done
|
||||
|||],
|
||||
},
|
||||
] else [],
|
||||
initContainers: [{
|
||||
name: 'pomerium-' + svc + '-certs',
|
||||
image: 'buildpack-deps:buster-curl',
|
||||
imagePullPolicy: 'Always',
|
||||
command: ['sh', '-c', |||
|
||||
cp /incoming-certs/* /usr/local/share/ca-certificates
|
||||
update-ca-certificates
|
||||
|||],
|
||||
volumeMounts: [
|
||||
{
|
||||
name: 'incoming-certs',
|
||||
mountPath: '/incoming-certs',
|
||||
},
|
||||
{
|
||||
name: 'outgoing-certs',
|
||||
mountPath: '/etc/ssl/certs',
|
||||
},
|
||||
],
|
||||
}],
|
||||
containers: [{
|
||||
name: 'pomerium-' + svc,
|
||||
image: 'pomerium/pomerium:dev',
|
||||
|
@ -292,15 +180,9 @@ local PomeriumDeployment = function(svc) {
|
|||
}],
|
||||
volumes: [
|
||||
{
|
||||
name: 'trusted-incoming-certs',
|
||||
secret: {
|
||||
secretName: 'pomerium-trusted-tls',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'wrongly-named-incoming-certs',
|
||||
secret: {
|
||||
secretName: 'pomerium-wrongly-named-tls',
|
||||
name: 'incoming-certs',
|
||||
configMap: {
|
||||
name: 'pomerium-cas',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -348,8 +230,7 @@ local PomeriumIngress = function() {
|
|||
'forward-authenticate.localhost.pomerium.io',
|
||||
'httpecho.localhost.pomerium.io',
|
||||
'httpdetails.localhost.pomerium.io',
|
||||
'enabled-ws-echo.localhost.pomerium.io',
|
||||
'disabled-ws-echo.localhost.pomerium.io',
|
||||
'restricted-httpdetails.localhost.pomerium.io',
|
||||
],
|
||||
|
||||
apiVersion: 'extensions/v1beta1',
|
||||
|
@ -369,7 +250,7 @@ local PomeriumIngress = function() {
|
|||
hosts: [
|
||||
'authenticate.localhost.pomerium.io',
|
||||
] + proxyHosts,
|
||||
secretName: 'pomerium-trusted-tls',
|
||||
secretName: 'pomerium-tls',
|
||||
},
|
||||
],
|
||||
rules: [
|
||||
|
@ -421,7 +302,7 @@ local PomeriumForwardAuthIngress = function() {
|
|||
hosts: [
|
||||
'fa-httpdetails.localhost.pomerium.io',
|
||||
],
|
||||
secretName: 'pomerium-trusted-tls',
|
||||
secretName: 'pomerium-tls',
|
||||
},
|
||||
],
|
||||
rules: [
|
||||
|
@ -455,9 +336,8 @@ local PomeriumForwardAuthIngress = function() {
|
|||
kind: 'List',
|
||||
items: [
|
||||
PomeriumConfigMap(),
|
||||
PomeriumTLSSecret('trusted'),
|
||||
PomeriumTLSSecret('untrusted'),
|
||||
PomeriumTLSSecret('wrongly-named'),
|
||||
PomeriumCAsConfigMap(),
|
||||
PomeriumTLSSecret(),
|
||||
PomeriumService('authenticate'),
|
||||
PomeriumDeployment('authenticate'),
|
||||
PomeriumService('authorize'),
|
||||
|
|
|
@ -73,7 +73,7 @@ local Ingress = function() {
|
|||
hosts: [
|
||||
'openid.localhost.pomerium.io',
|
||||
],
|
||||
secretName: 'pomerium-trusted-tls',
|
||||
secretName: 'pomerium-tls',
|
||||
},
|
||||
],
|
||||
rules: [
|
||||
|
|
|
@ -1,29 +1,5 @@
|
|||
{
|
||||
trusted: {
|
||||
cert: std.extVar('tls-trusted-cert'),
|
||||
key: std.extVar('tls-trusted-key'),
|
||||
ca: std.extVar('tls-trusted-ca'),
|
||||
client: {
|
||||
cert: std.extVar('tls-trusted-client-cert'),
|
||||
key: std.extVar('tls-trusted-client-key'),
|
||||
},
|
||||
},
|
||||
'wrongly-named': {
|
||||
cert: std.extVar('tls-wrongly-named-cert'),
|
||||
key: std.extVar('tls-wrongly-named-key'),
|
||||
ca: std.extVar('tls-wrongly-named-ca'),
|
||||
client: {
|
||||
cert: std.extVar('tls-wrongly-named-client-cert'),
|
||||
key: std.extVar('tls-wrongly-named-client-key'),
|
||||
},
|
||||
},
|
||||
untrusted: {
|
||||
cert: std.extVar('tls-untrusted-cert'),
|
||||
key: std.extVar('tls-untrusted-key'),
|
||||
ca: std.extVar('tls-untrusted-ca'),
|
||||
client: {
|
||||
cert: std.extVar('tls-untrusted-client-cert'),
|
||||
key: std.extVar('tls-untrusted-client-key'),
|
||||
},
|
||||
},
|
||||
cert: std.extVar('tls-cert'),
|
||||
key: std.extVar('tls-key'),
|
||||
ca: std.extVar('tls-ca'),
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
local backends = import './lib/backends.libsonnet';
|
||||
local httpdetails = import './lib/httpdetails.libsonnet';
|
||||
local nginxIngressController = import './lib/nginx-ingress-controller.libsonnet';
|
||||
local pomerium = import './lib/pomerium.libsonnet';
|
||||
local openid = import './lib/reference-openid-provider.libsonnet';
|
||||
|
@ -6,5 +6,5 @@ local openid = import './lib/reference-openid-provider.libsonnet';
|
|||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'List',
|
||||
items: nginxIngressController.items + pomerium.items + openid.items + backends.items,
|
||||
items: nginxIngressController.items + pomerium.items + openid.items + httpdetails.items,
|
||||
}
|
||||
|
|
|
@ -1,338 +0,0 @@
|
|||
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) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
t.Run("enabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
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 := 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")
|
||||
})
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
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 := client.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) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
t.Run("enabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/preserve-host-header-enabled", 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()
|
||||
|
||||
var result struct {
|
||||
Host string `json:"host"`
|
||||
}
|
||||
err = json.NewDecoder(res.Body).Decode(&result)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, "httpdetails.localhost.pomerium.io", result.Host,
|
||||
"destination host should be preserved in %v", result)
|
||||
})
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/preserve-host-header-disabled", 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()
|
||||
|
||||
var result struct {
|
||||
Host string `json:"host"`
|
||||
}
|
||||
err = json.NewDecoder(res.Body).Decode(&result)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
assert.NotEqual(t, "httpdetails.localhost.pomerium.io", result.Host,
|
||||
"destination host should not be preserved in %v", result)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSetRequestHeaders(t *testing.T) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
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()
|
||||
|
||||
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 TestWebsocket(t *testing.T) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
ws, _, err := (&websocket.Dialer{
|
||||
NetDialContext: testcluster.Transport.DialContext,
|
||||
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{
|
||||
NetDialContext: testcluster.Transport.DialContext,
|
||||
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 TestTLSSkipVerify(t *testing.T) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
t.Run("enabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/tls-skip-verify-enabled", 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)
|
||||
})
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/tls-skip-verify-disabled", 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.StatusBadGateway, res.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSServerName(t *testing.T) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
t.Run("enabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/tls-server-name-enabled", 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)
|
||||
})
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/tls-server-name-disabled", 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.StatusBadGateway, res.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSCustomCA(t *testing.T) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
t.Run("enabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/tls-custom-ca-enabled", 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)
|
||||
})
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/tls-custom-ca-disabled", 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.StatusBadGateway, res.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSClientCert(t *testing.T) {
|
||||
ctx := mainCtx
|
||||
ctx, clearTimeout := context.WithTimeout(ctx, time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
t.Run("enabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/tls-client-cert-enabled", 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)
|
||||
})
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
client := testcluster.NewHTTPClient()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpdetails.localhost.pomerium.io/tls-client-cert-disabled", 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.StatusBadGateway, res.StatusCode)
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue