Merge remote-tracking branch 'upstream/main' into token-endpoint
This commit is contained in:
commit
2dc3ab1840
@ -8,7 +8,7 @@ Please see the [Code of Conduct](./CODE_OF_CONDUCT.md).
|
|||||||
|
|
||||||
## Project Scope
|
## Project Scope
|
||||||
|
|
||||||
Learn about the [scope](doc/scope.md) of the project.
|
Learn about the [scope](https://pinniped.dev/docs/scope/) of the project.
|
||||||
|
|
||||||
## Meeting with the Maintainers
|
## Meeting with the Maintainers
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<img src="doc/img/pinniped_logo.svg" alt="Pinniped Logo" width="100%"/>
|
<img src="site/content/docs/img/pinniped_logo.svg" alt="Pinniped Logo" width="100%"/>
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@ -28,13 +28,13 @@ credential for a short-lived, cluster-specific credential. Pinniped supports var
|
|||||||
IDP types and implements different integration strategies for various Kubernetes
|
IDP types and implements different integration strategies for various Kubernetes
|
||||||
distributions to make authentication possible.
|
distributions to make authentication possible.
|
||||||
|
|
||||||
To learn more, see [doc/architecture.md](doc/architecture.md).
|
To learn more, see [architecture](https://pinniped.dev/docs/architecture/).
|
||||||
|
|
||||||
<img src="doc/img/pinniped_architecture.svg" alt="Pinniped Architecture Sketch" width="300px"/>
|
<img src="site/content/docs/img/pinniped_architecture.svg" alt="Pinniped Architecture Sketch" width="300px"/>
|
||||||
|
|
||||||
## Trying Pinniped
|
## Trying Pinniped
|
||||||
|
|
||||||
Care to kick the tires? It's easy to [install and try Pinniped](doc/demo.md).
|
Care to kick the tires? It's easy to [install and try Pinniped](https://pinniped.dev/docs/demo/).
|
||||||
|
|
||||||
## Discussion
|
## Discussion
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ kubectl get secret local-user-authenticator-tls-serving-certificate --namespace
|
|||||||
|
|
||||||
When installing Pinniped on the same cluster, configure local-user-authenticator as an Identity Provider for Pinniped
|
When installing Pinniped on the same cluster, configure local-user-authenticator as an Identity Provider for Pinniped
|
||||||
using the webhook URL `https://local-user-authenticator.local-user-authenticator.svc/authenticate`
|
using the webhook URL `https://local-user-authenticator.local-user-authenticator.svc/authenticate`
|
||||||
along with the CA bundle fetched by the above command. See [doc/demo.md](../../doc/demo.md) for an example.
|
along with the CA bundle fetched by the above command. See [demo](https://pinniped.dev/docs/demo/) for an example.
|
||||||
|
|
||||||
## Optional: Manually Testing the Webhook Endpoint After Installing
|
## Optional: Manually Testing the Webhook Endpoint After Installing
|
||||||
|
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
# Architecture
|
|
||||||
|
|
||||||
The principal purpose of Pinniped is to allow users to access Kubernetes
|
|
||||||
clusters. Pinniped hopes to enable this access across a wide range of Kubernetes
|
|
||||||
environments with zero configuration.
|
|
||||||
|
|
||||||
This integration is implemented using a credential exchange API which takes as
|
|
||||||
input a credential from the external IDP and returns a credential which is understood by the host
|
|
||||||
Kubernetes cluster.
|
|
||||||
|
|
||||||
<img src="img/pinniped_architecture.svg" alt="Pinniped Architecture Sketch" width="300px"/>
|
|
||||||
|
|
||||||
Pinniped supports various IDP types and implements different integration strategies
|
|
||||||
for various Kubernetes distributions to make authentication possible.
|
|
||||||
|
|
||||||
## Supported Kubernetes Cluster Types
|
|
||||||
|
|
||||||
Pinniped supports the following types of Kubernetes clusters:
|
|
||||||
|
|
||||||
- Clusters where the Kube Controller Manager pod is accessible from Pinniped's pods.
|
|
||||||
|
|
||||||
Support for other types of Kubernetes distributions is coming soon.
|
|
||||||
|
|
||||||
## External Identity Provider Integrations
|
|
||||||
|
|
||||||
Pinniped will consume identity from one or more external identity providers
|
|
||||||
(IDPs). Administrators will configure external IDPs via Kubernetes custom
|
|
||||||
resources allowing Pinniped to be managed using GitOps and standard Kubernetes tools.
|
|
||||||
|
|
||||||
Pinniped supports the following external IDP types.
|
|
||||||
|
|
||||||
1. Any webhook which implements the
|
|
||||||
[Kubernetes TokenReview API](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication).
|
|
||||||
|
|
||||||
In addition to allowing the integration of any existing IDP which implements this API, webhooks also
|
|
||||||
serve as an extension point for Pinniped by allowing for integration of arbitrary custom authenticators.
|
|
||||||
While a custom implementation may be in any language or framework, this project provides a
|
|
||||||
sample implementation in Golang. See the `ServeHTTP` method of
|
|
||||||
[cmd/local-user-authenticator/main.go](../cmd/local-user-authenticator/main.go).
|
|
||||||
|
|
||||||
More IDP types are coming soon.
|
|
||||||
|
|
||||||
## Cluster Integration Strategies
|
|
||||||
|
|
||||||
Pinniped will issue a cluster credential by leveraging cluster-specific
|
|
||||||
functionality. In the near term, cluster integrations will happen via different
|
|
||||||
cluster-specific flows depending on the type of cluster. In the longer term,
|
|
||||||
Pinniped hopes to contribute and leverage upstream Kubernetes extension points that
|
|
||||||
cleanly enable this integration.
|
|
||||||
|
|
||||||
Pinniped supports the following cluster integration strategies.
|
|
||||||
|
|
||||||
1. Pinniped hosts a credential exchange API endpoint via a Kubernetes aggregated API server.
|
|
||||||
This API returns a new cluster-specific credential using the cluster's signing keypair to
|
|
||||||
issue short-lived cluster certificates. (In the future, when the Kubernetes CSR API
|
|
||||||
provides a way to issue short-lived certificates, then the Pinniped credential exchange API
|
|
||||||
will use that instead of using the cluster's signing keypair.)
|
|
||||||
|
|
||||||
More cluster integration strategies are coming soon, which will allow Pinniped to
|
|
||||||
support more Kubernetes cluster types.
|
|
||||||
|
|
||||||
## `kubectl` Integration
|
|
||||||
|
|
||||||
With any of the above IDPs and integration strategies, `kubectl` commands receive the
|
|
||||||
cluster-specific credential via a
|
|
||||||
[Kubernetes client-go credential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins).
|
|
||||||
Users may use the Pinniped CLI as the credential plugin, or they may use any proprietary CLI
|
|
||||||
built with the [Pinniped Go client library](../generated).
|
|
||||||
|
|
||||||
## Example Cluster Authentication Sequence Diagram
|
|
||||||
|
|
||||||
This diagram demonstrates using `kubectl get pods` with the Pinniped CLI configured as the credential plugin,
|
|
||||||
and with a webhook IDP configured as the identity provider for the Pinniped server.
|
|
||||||
|
|
||||||
![example-cluster-authentication-sequence-diagram](img/pinniped.svg)
|
|
198
doc/demo.md
198
doc/demo.md
@ -1,198 +0,0 @@
|
|||||||
# Trying Pinniped
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
1. A Kubernetes cluster of a type supported by Pinniped as described in [doc/architecture.md](../doc/architecture.md).
|
|
||||||
|
|
||||||
Don't have a cluster handy? Consider using [kind](https://kind.sigs.k8s.io/) on your local machine.
|
|
||||||
See below for an example of using kind.
|
|
||||||
|
|
||||||
1. An identity provider of a type supported by Pinniped as described in [doc/architecture.md](../doc/architecture.md).
|
|
||||||
|
|
||||||
Don't have an identity provider of a type supported by Pinniped handy? No problem, there is a demo identity provider
|
|
||||||
available. Start by installing local-user-authenticator on the same cluster where you would like to try Pinniped
|
|
||||||
by following the directions in [deploy/local-user-authenticator/README.md](../deploy/local-user-authenticator/README.md).
|
|
||||||
See below for an example of deploying this on kind.
|
|
||||||
|
|
||||||
1. A kubeconfig where the current context points to the cluster and has admin-like
|
|
||||||
privileges on that cluster.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Installing and trying Pinniped on any cluster will consist of the following general steps. See the next section below
|
|
||||||
for a more specific example of installing onto a local kind cluster, including the exact commands to use for that case.
|
|
||||||
|
|
||||||
1. Install Pinniped. See [deploy/concierge/README.md](../deploy/concierge/README.md).
|
|
||||||
1. Download the Pinniped CLI from [Pinniped's github Releases page](https://github.com/vmware-tanzu/pinniped/releases/latest).
|
|
||||||
1. Generate a kubeconfig using the Pinniped CLI. Run `pinniped get-kubeconfig --help` for more information.
|
|
||||||
1. Run `kubectl` commands using the generated kubeconfig. Pinniped will automatically be used for authentication during those commands.
|
|
||||||
|
|
||||||
## Example of Deploying on kind
|
|
||||||
|
|
||||||
[kind](https://kind.sigs.k8s.io) is a tool for creating and managing Kubernetes clusters on your local machine
|
|
||||||
which uses Docker containers as the cluster's "nodes". This is a convenient way to try out Pinniped on a local
|
|
||||||
non-production cluster.
|
|
||||||
|
|
||||||
The following steps will deploy the latest release of Pinniped on kind using the local-user-authenticator component
|
|
||||||
as the identity provider.
|
|
||||||
|
|
||||||
<!-- The following image was uploaded to GitHub's CDN using this awesome trick: https://gist.github.com/vinkla/dca76249ba6b73c5dd66a4e986df4c8d -->
|
|
||||||
<p align="center" width="100%">
|
|
||||||
<img
|
|
||||||
src="https://user-images.githubusercontent.com/25013435/95272990-b2ea9780-07f6-11eb-994d-872e3cb68457.gif"
|
|
||||||
alt="Pinniped Installation Demo"
|
|
||||||
width="80%"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
1. Install the tools required for the following steps.
|
|
||||||
|
|
||||||
- [Install kind](https://kind.sigs.k8s.io/docs/user/quick-start/), if not already installed. e.g. `brew install kind` on MacOS.
|
|
||||||
|
|
||||||
- kind depends on Docker. If not already installed, [install Docker](https://docs.docker.com/get-docker/), e.g. `brew cask install docker` on MacOS.
|
|
||||||
|
|
||||||
- This demo requires `kubectl`, which comes with Docker, or can be [installed separately](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
|
|
||||||
|
|
||||||
- This demo requires a tool capable of generating a `bcrypt` hash in order to interact with
|
|
||||||
the webhook. The example below uses `htpasswd`, which is installed on most macOS systems, and can be
|
|
||||||
installed on some Linux systems via the `apache2-utils` package (e.g., `apt-get install
|
|
||||||
apache2-utils`).
|
|
||||||
|
|
||||||
- One of the steps below optionally uses `jq` to help find the latest release version number. It is not required.
|
|
||||||
Install `jq` if you would like, e.g. `brew install jq` on MacOS.
|
|
||||||
|
|
||||||
1. Create a new Kubernetes cluster using `kind create cluster`. Optionally provide a cluster name using the `--name` flag.
|
|
||||||
kind will automatically update your kubeconfig to point to the new cluster as a user with admin-like permissions.
|
|
||||||
|
|
||||||
1. Query GitHub's API for the git tag of the latest Pinniped
|
|
||||||
[release](https://github.com/vmware-tanzu/pinniped/releases/latest).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pinniped_version=$(curl https://api.github.com/repos/vmware-tanzu/pinniped/releases/latest -s | jq .name -r)
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, [any release version](https://github.com/vmware-tanzu/pinniped/releases)
|
|
||||||
number can be manually selected.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Example of manually choosing a release version...
|
|
||||||
pinniped_version=v0.2.0
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Deploy the local-user-authenticator app. This is a demo identity provider. In production, you would use your
|
|
||||||
real identity provider, and therefore would not need to deploy or configure local-user-authenticator.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl apply -f https://github.com/vmware-tanzu/pinniped/releases/download/$pinniped_version/install-local-user-authenticator.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
The `install-local-user-authenticator.yaml` file includes the default deployment options.
|
|
||||||
If you would prefer to customize the available options, please
|
|
||||||
see [deploy/local-user-authenticator/README.md](../deploy/local-user-authenticator/README.md)
|
|
||||||
for instructions on how to deploy using `ytt`.
|
|
||||||
|
|
||||||
1. Create a test user named `pinny-the-seal` in the local-user-authenticator identity provider.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl create secret generic pinny-the-seal \
|
|
||||||
--namespace local-user-authenticator \
|
|
||||||
--from-literal=groups=group1,group2 \
|
|
||||||
--from-literal=passwordHash=$(htpasswd -nbBC 10 x password123 | sed -e "s/^x://")
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Fetch the auto-generated CA bundle for the local-user-authenticator's HTTP TLS endpoint.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator \
|
|
||||||
-o jsonpath={.data.caCertificate} \
|
|
||||||
| tee /tmp/local-user-authenticator-ca-base64-encoded
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Deploy the Pinniped concierge.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl apply -f https://github.com/vmware-tanzu/pinniped/releases/download/$pinniped_version/install-pinniped-concierge.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
The `install-pinniped-concierge.yaml` file includes the default deployment options.
|
|
||||||
If you would prefer to customize the available options, please see [deploy/concierge/README.md](../deploy/concierge/README.md)
|
|
||||||
for instructions on how to deploy using `ytt`.
|
|
||||||
|
|
||||||
1. Create a `WebhookAuthenticator` object to configure Pinniped to authenticate using local-user-authenticator.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat <<EOF | kubectl create --namespace pinniped-concierge -f -
|
|
||||||
apiVersion: authentication.concierge.pinniped.dev/v1alpha1
|
|
||||||
kind: WebhookAuthenticator
|
|
||||||
metadata:
|
|
||||||
name: local-user-authenticator
|
|
||||||
spec:
|
|
||||||
endpoint: https://local-user-authenticator.local-user-authenticator.svc/authenticate
|
|
||||||
tls:
|
|
||||||
certificateAuthorityData: $(cat /tmp/local-user-authenticator-ca-base64-encoded)
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Download the latest version of the Pinniped CLI binary for your platform
|
|
||||||
from Pinniped's [latest release](https://github.com/vmware-tanzu/pinniped/releases/latest).
|
|
||||||
|
|
||||||
1. Move the Pinniped CLI binary to your preferred filename and directory. Add the executable bit,
|
|
||||||
e.g. `chmod +x /usr/local/bin/pinniped`.
|
|
||||||
|
|
||||||
1. Generate a kubeconfig for the current cluster. Use `--token` to include a token which should
|
|
||||||
allow you to authenticate as the user that you created above.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pinniped get-kubeconfig --pinniped-namespace pinniped-concierge --token "pinny-the-seal:password123" --authenticator-type webhook --authenticator-name local-user-authenticator > /tmp/pinniped-kubeconfig
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are using MacOS, you may get an error dialog that says
|
|
||||||
`“pinniped” cannot be opened because the developer cannot be verified`. Cancel this dialog, open System Preferences,
|
|
||||||
click on Security & Privacy, and click the Allow Anyway button next to the Pinniped message.
|
|
||||||
Run the above command again and another dialog will appear saying
|
|
||||||
`macOS cannot verify the developer of “pinniped”. Are you sure you want to open it?`.
|
|
||||||
Click Open to allow the command to proceed.
|
|
||||||
|
|
||||||
Note that the above command will print a warning to the screen. You can ignore this warning.
|
|
||||||
Pinniped tries to auto-discover the URL for the Kubernetes API server, but it is not able
|
|
||||||
to do so on kind clusters. The warning is just letting you know that the Pinniped CLI decided
|
|
||||||
to ignore the auto-discovery URL and instead use the URL from your existing kubeconfig.
|
|
||||||
|
|
||||||
1. Try using the generated kubeconfig to issue arbitrary `kubectl` commands as
|
|
||||||
the `pinny-the-seal` user.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl --kubeconfig /tmp/pinniped-kubeconfig get pods -n pinniped-concierge
|
|
||||||
```
|
|
||||||
|
|
||||||
Because this user has no RBAC permissions on this cluster, the previous command
|
|
||||||
results in the error `Error from server (Forbidden): pods is forbidden: User "pinny-the-seal" cannot list resource "pods" in API group "" in the namespace "pinniped"`.
|
|
||||||
However, this does prove that you are authenticated and acting as the `pinny-the-seal` user.
|
|
||||||
|
|
||||||
1. As the admin user, create RBAC rules for the test user to give them permissions to perform actions on the cluster.
|
|
||||||
For example, grant the test user permission to view all cluster resources.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl create clusterrolebinding pinny-can-read --clusterrole view --user pinny-the-seal
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Use the generated kubeconfig to issue arbitrary `kubectl` commands as the `pinny-the-seal` user.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl --kubeconfig /tmp/pinniped-kubeconfig get pods -n pinniped-concierge
|
|
||||||
```
|
|
||||||
|
|
||||||
The user has permission to list pods, so the command succeeds this time.
|
|
||||||
Pinniped has provided authentication into the cluster for your `kubectl` command! 🎉
|
|
||||||
|
|
||||||
1. Carry on issuing as many `kubectl` commands as you'd like as the `pinny-the-seal` user.
|
|
||||||
Each invocation will use Pinniped for authentication.
|
|
||||||
You may find it convenient to set the `KUBECONFIG` environment variable rather than passing `--kubeconfig` to each invocation.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export KUBECONFIG=/tmp/pinniped-kubeconfig
|
|
||||||
kubectl get namespaces
|
|
||||||
kubectl get pods -A
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Profit! 💰
|
|
@ -1,12 +0,0 @@
|
|||||||
# `doc/img` README
|
|
||||||
|
|
||||||
## How to Update these Images
|
|
||||||
|
|
||||||
- [pinniped.svg](pinniped.svg) was generated using [`plantuml`](https://plantuml.com/).
|
|
||||||
To regenerate the image, run `plantuml -tsvg pinniped.txt` from this directory.
|
|
||||||
|
|
||||||
- [pinniped_architecture.svg](pinniped_architecture.svg) was created on [draw.io](https://draw.io).
|
|
||||||
It can be opened again for editing on that site by choosing "File" -> "Open from" -> "Device".
|
|
||||||
Because it includes embedded icons it should be exported using "File" -> "Export as" -> "SVG",
|
|
||||||
with the "Transparent Background", "Embed Images", and "Include a copy of my diagram" options
|
|
||||||
checked. The icons in this diagram are from their "CAE" shapes set.
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 43 KiB |
@ -1,61 +0,0 @@
|
|||||||
@startuml "pinniped"
|
|
||||||
|
|
||||||
!define K8S_BLUE #326CE5
|
|
||||||
!define K8S_SPRITES_URL https://raw.githubusercontent.com/michiel/plantuml-kubernetes-sprites/master/resource
|
|
||||||
!include K8S_SPRITES_URL/k8s-sprites-unlabeled-25pct.iuml
|
|
||||||
|
|
||||||
participant "User" as USER << ($pod{scale=0.30},K8S_BLUE) >> #LightGreen
|
|
||||||
participant "Kubectl" as KUBECTL << ($ing{scale=0.30},K8S_BLUE) >> #LightSteelBlue
|
|
||||||
participant "Proprietary CLI" as CLI << ($svc{scale=0.30},K8S_BLUE) >> #LightPink
|
|
||||||
participant "Pinniped" as PINNIPED << ($node{scale=0.30},K8S_BLUE) >> #LightGray
|
|
||||||
participant "TokenReview Webhook" as WEBHOOK << ($pod{scale=0.30},K8S_BLUE) >> #LightPink
|
|
||||||
participant "Kubernetes API" as API << ($node{scale=0.30},K8S_BLUE) >> #LightSteelBlue
|
|
||||||
|
|
||||||
legend
|
|
||||||
# <back:lightsalmon>Message contains upstream IDP credentials</back>
|
|
||||||
# <back:lightgreen>Message contains cluster-specific credentials</back>
|
|
||||||
end legend
|
|
||||||
|
|
||||||
USER -> KUBECTL : ""kubectl get pods""
|
|
||||||
activate KUBECTL
|
|
||||||
|
|
||||||
group Acquire cluster-specific credential
|
|
||||||
|
|
||||||
KUBECTL -> CLI : Get cluster-specific credential
|
|
||||||
activate CLI
|
|
||||||
|
|
||||||
CLI -> CLI : Retrieve upstream IDP credential in\norganization-specific way
|
|
||||||
|
|
||||||
CLI -> PINNIPED : <back:lightsalmon>""POST /apis/pinniped.dev/...""</back>
|
|
||||||
activate PINNIPED
|
|
||||||
|
|
||||||
PINNIPED -> WEBHOOK : <back:lightsalmon>""POST /authenticate""</back>
|
|
||||||
activate WEBHOOK
|
|
||||||
|
|
||||||
WEBHOOK -> PINNIPED : ""200 OK"" with user and group information
|
|
||||||
deactivate WEBHOOK
|
|
||||||
|
|
||||||
PINNIPED -> PINNIPED : Issue short-lived cluster-specific credential\nwith user and group information
|
|
||||||
|
|
||||||
PINNIPED -> CLI : <back:lightgreen>""200 OK""</back>
|
|
||||||
deactivate PINNIPED
|
|
||||||
|
|
||||||
CLI -> KUBECTL : Here is a cluster-specific credential
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
group Authenticate to cluster with cluster-specific credential
|
|
||||||
|
|
||||||
KUBECTL -> API : <back:lightgreen>""GET /api/v1/pods""</back>
|
|
||||||
activate API
|
|
||||||
|
|
||||||
API -> API : Glean user and group information from\ncluster-specific credential
|
|
||||||
|
|
||||||
API -> KUBECTL : ""200 OK"" with pods
|
|
||||||
deactivate API
|
|
||||||
|
|
||||||
deactivate KUBECTL
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
@enduml
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 79 KiB |
@ -1,68 +0,0 @@
|
|||||||
<svg id="artwork" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 486 158"><metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
|
||||||
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 6.0-c002 79.164352, 2020/01/30-15:50:38 ">
|
|
||||||
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
|
||||||
<rdf:Description rdf:about=""
|
|
||||||
xmlns:lr="http://ns.adobe.com/lightroom/1.0/"
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
|
|
||||||
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
|
|
||||||
xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#">
|
|
||||||
<lr:hierarchicalSubject>
|
|
||||||
<rdf:Bag>
|
|
||||||
<rdf:li>open source identity</rdf:li>
|
|
||||||
<rdf:li>open source identity|636062</rdf:li>
|
|
||||||
<rdf:li>open source identity|Pinniped</rdf:li>
|
|
||||||
</rdf:Bag>
|
|
||||||
</lr:hierarchicalSubject>
|
|
||||||
<dc:subject>
|
|
||||||
<rdf:Bag>
|
|
||||||
<rdf:li>open source identity</rdf:li>
|
|
||||||
<rdf:li>636062</rdf:li>
|
|
||||||
<rdf:li>Pinniped</rdf:li>
|
|
||||||
</rdf:Bag>
|
|
||||||
</dc:subject>
|
|
||||||
<xmp:MetadataDate>2020-09-17T16:06:40-07:00</xmp:MetadataDate>
|
|
||||||
<xmpMM:InstanceID>xmp.iid:932334bf-97ee-471a-96c9-c4e5ff526fe4</xmpMM:InstanceID>
|
|
||||||
<xmpMM:DocumentID>xmp.did:38396587-b56b-42c3-8f3e-f8e9c91f532b</xmpMM:DocumentID>
|
|
||||||
<xmpMM:OriginalDocumentID>xmp.did:38396587-b56b-42c3-8f3e-f8e9c91f532b</xmpMM:OriginalDocumentID>
|
|
||||||
<xmpMM:History>
|
|
||||||
<rdf:Seq>
|
|
||||||
<rdf:li>
|
|
||||||
<rdf:Description>
|
|
||||||
<stEvt:action>saved</stEvt:action>
|
|
||||||
<stEvt:instanceID>xmp.iid:38396587-b56b-42c3-8f3e-f8e9c91f532b</stEvt:instanceID>
|
|
||||||
<stEvt:when>2020-09-17T16:06:35-07:00</stEvt:when>
|
|
||||||
<stEvt:softwareAgent>Adobe Bridge 2020 (Macintosh)</stEvt:softwareAgent>
|
|
||||||
<stEvt:changed>/metadata</stEvt:changed>
|
|
||||||
</rdf:Description>
|
|
||||||
</rdf:li>
|
|
||||||
<rdf:li>
|
|
||||||
<rdf:Description>
|
|
||||||
<stEvt:action>saved</stEvt:action>
|
|
||||||
<stEvt:instanceID>xmp.iid:932334bf-97ee-471a-96c9-c4e5ff526fe4</stEvt:instanceID>
|
|
||||||
<stEvt:when>2020-09-17T16:06:40-07:00</stEvt:when>
|
|
||||||
<stEvt:softwareAgent>Adobe Bridge 2020 (Macintosh)</stEvt:softwareAgent>
|
|
||||||
<stEvt:changed>/metadata</stEvt:changed>
|
|
||||||
</rdf:Description>
|
|
||||||
</rdf:li>
|
|
||||||
</rdf:Seq>
|
|
||||||
</xmpMM:History>
|
|
||||||
</rdf:Description>
|
|
||||||
</rdf:RDF>
|
|
||||||
</x:xmpmeta>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<?xpacket end="w"?></metadata>
|
|
||||||
<defs><style>.cls-1{fill:#717073;}.cls-2{fill:#727174;}.cls-3{fill:#fff;}.cls-4{fill:#78be43;}.cls-5{fill:#1abfd3;}.cls-6{fill:#79459b;}.cls-7{fill:#1e4488;}.cls-8{fill:#218fcf;}</style></defs><path class="cls-1" d="M170.52,58.21h16.74a17.43,17.43,0,0,1,7.68,1.68,13.45,13.45,0,0,1,5.49,4.71,12.54,12.54,0,0,1,0,13.62,13.45,13.45,0,0,1-5.49,4.71,17.43,17.43,0,0,1-7.68,1.68H175.2V99.43h-4.68Zm15.9,22a13.23,13.23,0,0,0,8.19-2.34,8.21,8.21,0,0,0,0-12.84,13.23,13.23,0,0,0-8.19-2.34H175.2V80.17Z"/><path class="cls-1" d="M209.82,58.21h4.68V99.43h-4.68Z"/><path class="cls-1" d="M225.78,58.21h4.68L256,91.75V58.21h4.68V99.43H256L230.46,65.89V99.43h-4.68Z"/><path class="cls-1" d="M272,58.21h4.68l25.56,33.54V58.21h4.68V99.43h-4.68L276.66,65.89V99.43H272Z"/><path class="cls-1" d="M318.18,58.21h4.68V99.43h-4.68Z"/><path class="cls-1" d="M334.14,58.21h16.74a17.46,17.46,0,0,1,7.68,1.68,13.51,13.51,0,0,1,5.49,4.71,12.54,12.54,0,0,1,0,13.62,13.51,13.51,0,0,1-5.49,4.71,17.46,17.46,0,0,1-7.68,1.68H338.82V99.43h-4.68Zm15.9,22a13.23,13.23,0,0,0,8.19-2.34,8.21,8.21,0,0,0,0-12.84A13.23,13.23,0,0,0,350,62.65H338.82V80.17Z"/><path class="cls-1" d="M378.18,62.65V76.21h22.38v4.44H378.18V95H403v4.44H373.44V58.21H403v4.44Z"/><path class="cls-1" d="M411.12,58.21H425a24.6,24.6,0,0,1,11.54,2.64,19.73,19.73,0,0,1,7.92,7.32,21.2,21.2,0,0,1,0,21.27,19.66,19.66,0,0,1-7.92,7.35A24.6,24.6,0,0,1,425,99.43H411.12Zm13.92,37a19.21,19.21,0,0,0,9.08-2.1,15.61,15.61,0,0,0,6.25-5.82,17,17,0,0,0,0-16.89,15.68,15.68,0,0,0-6.25-5.79,19.21,19.21,0,0,0-9.08-2.1h-9.25v32.7Z"/><path class="cls-2" d="M91.14,25.5A52.5,52.5,0,1,0,143.64,78,52.51,52.51,0,0,0,91.14,25.5Zm0,95.33A42.83,42.83,0,1,1,134,78,42.83,42.83,0,0,1,91.14,120.83Z"/><circle class="cls-3" cx="91.33" cy="77.84" r="45.75"/><circle class="cls-4" cx="91.16" cy="76.71" r="8"/><path class="cls-5" d="M118.92,58.45l1.66,6.89,5.12-.66-3-12.42-.15-.5v0l-11.73-5.08-1.53,5,6.48,2.8L101.26,66.65a14.14,14.14,0,0,1,2.9,4.24Z"/><path class="cls-6" d="M66.46,54.41,73,51.61l-1.53-5L59.68,51.73v0l-.15.5-3,12.42,5.13.66,1.65-6.89L78.13,70.94A14.23,14.23,0,0,1,81,66.68Z"/><path class="cls-7" d="M57.49,82.82,59.21,76l-4.87-1.8L51.23,86.56l0,0,.31.42,8,9.94,3.66-3.66-4.47-5.51,19.82-4.35A14.23,14.23,0,0,1,77,78.54Z"/><path class="cls-7" d="M128,74.17,123.11,76l1.72,6.85-19.54-4.28a14.23,14.23,0,0,1-1.56,4.89l19.81,4.35-4.46,5.51L122.73,97l8-9.94.31-.42,0,0Z"/><path class="cls-6" d="M103.35,109l-7.08-.33-.79,5.11,12.76.58h.56l8.14-9.86-4.34-2.85-4.5,5.45-8.43-19a14.36,14.36,0,0,1-4.58,2.28Z"/><path class="cls-5" d="M74.24,107.08l-4.5-5.45-4.34,2.85,8.14,9.86h.56l12.76-.58-.78-5.11L79,109l8.26-18.57a14.28,14.28,0,0,1-4.59-2.27Z"/><path class="cls-8" d="M93.78,62.7V43.84L100.12,47l2.79-4.35L91.49,37,91,36.74h0l-11.44,5.7,2.8,4.37,6.33-3.15v19a14.59,14.59,0,0,1,2.49-.23A15,15,0,0,1,93.78,62.7Z"/></svg>
|
|
Before Width: | Height: | Size: 5.4 KiB |
32
doc/scope.md
32
doc/scope.md
@ -1,32 +0,0 @@
|
|||||||
# Project Scope
|
|
||||||
|
|
||||||
The Pinniped project is guided by the following principles.
|
|
||||||
* Pinniped lets you plug any external identitiy providers into
|
|
||||||
Kubernetes. These integrations follow enterprise-grade security principles.
|
|
||||||
* Pinniped is easy to install and use on any Kubernetes cluster via
|
|
||||||
distribution-specific integration mechanisms.
|
|
||||||
* Pinniped uses a declarative configuration via Kubernetes APIs.
|
|
||||||
* Pinniped provides optimal user experience when authenticating to many
|
|
||||||
clusters at one time.
|
|
||||||
* Pinniped provides enterprise-grade security posture via secure defaults and
|
|
||||||
revocable or very short-lived credentials.
|
|
||||||
* Where possible, Pinniped will contribute ideas and code to upstream
|
|
||||||
Kubernetes.
|
|
||||||
|
|
||||||
When contributing to Pinniped, please consider whether your contribution follows
|
|
||||||
these guiding principles.
|
|
||||||
|
|
||||||
## Out Of Scope
|
|
||||||
|
|
||||||
The following items are out of scope for the Pinniped project.
|
|
||||||
* Authorization.
|
|
||||||
* Standalone identity provider for general use.
|
|
||||||
* Machine-to-machine (service) identity.
|
|
||||||
* Running outside of Kubernetes.
|
|
||||||
|
|
||||||
## Roadmap
|
|
||||||
|
|
||||||
More details coming soon!
|
|
||||||
|
|
||||||
For more details on proposing features and bugs, check out our
|
|
||||||
[contributing](../CONTRIBUTING.md) doc.
|
|
@ -23,7 +23,10 @@ local_resource(
|
|||||||
#
|
#
|
||||||
|
|
||||||
# Render the IDP installation manifest using ytt.
|
# Render the IDP installation manifest using ytt.
|
||||||
k8s_yaml(local(['ytt','--file', '../../../test/deploy/dex']))
|
k8s_yaml(local(['ytt',
|
||||||
|
'--file', '../../../test/deploy/dex',
|
||||||
|
'--data-value', 'supervisor_redirect_uri=https://pinniped-supervisor-clusterip.supervisor.svc.cluster.local/some/path/callback',
|
||||||
|
]))
|
||||||
# Tell tilt to watch all of those files for changes.
|
# Tell tilt to watch all of those files for changes.
|
||||||
watch_file('../../../test/deploy/dex')
|
watch_file('../../../test/deploy/dex')
|
||||||
|
|
||||||
|
@ -184,6 +184,10 @@ if ! tilt_mode; then
|
|||||||
|
|
||||||
log_note "Deploying Dex to the cluster..."
|
log_note "Deploying Dex to the cluster..."
|
||||||
ytt --file . >"$manifest"
|
ytt --file . >"$manifest"
|
||||||
|
ytt --file . \
|
||||||
|
--data-value "supervisor_redirect_uri=https://pinniped-supervisor-clusterip.supervisor.svc.cluster.local/some/path/callback" \
|
||||||
|
>"$manifest"
|
||||||
|
|
||||||
kubectl apply --dry-run=client -f "$manifest" # Validate manifest schema.
|
kubectl apply --dry-run=client -f "$manifest" # Validate manifest schema.
|
||||||
kapp deploy --yes --app dex --diff-changes --file "$manifest"
|
kapp deploy --yes --app dex --diff-changes --file "$manifest"
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ func addCSRFSetCookieHeader(w http.ResponseWriter, csrfValue csrftoken.CSRFToken
|
|||||||
Name: oidc.CSRFCookieName,
|
Name: oidc.CSRFCookieName,
|
||||||
Value: encodedCSRFValue,
|
Value: encodedCSRFValue,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
SameSite: http.SameSiteStrictMode,
|
SameSite: http.SameSiteLaxMode,
|
||||||
Secure: true,
|
Secure: true,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
})
|
})
|
||||||
|
@ -753,7 +753,7 @@ func TestAuthorizationEndpoint(t *testing.T) {
|
|||||||
if test.wantCSRFValueInCookieHeader != "" {
|
if test.wantCSRFValueInCookieHeader != "" {
|
||||||
require.Len(t, rsp.Header().Values("Set-Cookie"), 1)
|
require.Len(t, rsp.Header().Values("Set-Cookie"), 1)
|
||||||
actualCookie := rsp.Header().Get("Set-Cookie")
|
actualCookie := rsp.Header().Get("Set-Cookie")
|
||||||
regex := regexp.MustCompile("__Host-pinniped-csrf=([^;]+); Path=/; HttpOnly; Secure; SameSite=Strict")
|
regex := regexp.MustCompile("__Host-pinniped-csrf=([^;]+); Path=/; HttpOnly; Secure; SameSite=Lax")
|
||||||
submatches := regex.FindStringSubmatch(actualCookie)
|
submatches := regex.FindStringSubmatch(actualCookie)
|
||||||
require.Len(t, submatches, 2)
|
require.Len(t, submatches, 2)
|
||||||
captured := submatches[1]
|
captured := submatches[1]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# doc/img README
|
# site/content/docs/img README
|
||||||
|
|
||||||
## How to Update these Images
|
## How to Update these Images
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<div class="wrapper grid two">
|
<div class="wrapper grid two">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<p class="strong">Introduction to Pinniped</p>
|
<p class="strong">Introduction to Pinniped</p>
|
||||||
<p><a href="https://github.com/vmware-tanzu/pinniped/blob/main/doc/demo.md">Learn how Pinniped</a> provides identity services to Kubernetes</p>
|
<p><a href="https://pinniped.dev/docs/demo/">Learn how Pinniped</a> provides identity services to Kubernetes</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<p class="strong">How do you use Pinniped?</p>
|
<p class="strong">How do you use Pinniped?</p>
|
||||||
|
@ -28,7 +28,7 @@ staticClients:
|
|||||||
name: 'Pinniped Supervisor'
|
name: 'Pinniped Supervisor'
|
||||||
secret: pinniped-supervisor-secret
|
secret: pinniped-supervisor-secret
|
||||||
redirectURIs:
|
redirectURIs:
|
||||||
- https://pinniped-supervisor-clusterip.supervisor.svc.cluster.local/some/path/callback
|
- #@ data.values.supervisor_redirect_uri
|
||||||
enablePasswordDB: true
|
enablePasswordDB: true
|
||||||
staticPasswords:
|
staticPasswords:
|
||||||
- username: "pinny"
|
- username: "pinny"
|
||||||
|
@ -20,6 +20,9 @@ spec:
|
|||||||
labels:
|
labels:
|
||||||
app: proxy
|
app: proxy
|
||||||
spec:
|
spec:
|
||||||
|
volumes:
|
||||||
|
- name: log-dir
|
||||||
|
emptyDir: {}
|
||||||
containers:
|
containers:
|
||||||
- name: proxy
|
- name: proxy
|
||||||
image: docker.io/getpinniped/test-forward-proxy
|
image: docker.io/getpinniped/test-forward-proxy
|
||||||
@ -34,6 +37,9 @@ spec:
|
|||||||
limits:
|
limits:
|
||||||
cpu: "10m"
|
cpu: "10m"
|
||||||
memory: "64Mi"
|
memory: "64Mi"
|
||||||
|
volumeMounts:
|
||||||
|
- name: log-dir
|
||||||
|
mountPath: "/var/log/squid/"
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
tcpSocket:
|
tcpSocket:
|
||||||
port: http
|
port: http
|
||||||
@ -41,6 +47,16 @@ spec:
|
|||||||
timeoutSeconds: 5
|
timeoutSeconds: 5
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
failureThreshold: 2
|
failureThreshold: 2
|
||||||
|
- name: accesslogs
|
||||||
|
image: debian:10.6-slim
|
||||||
|
command:
|
||||||
|
- "/bin/sh"
|
||||||
|
- "-c"
|
||||||
|
args:
|
||||||
|
- tail -F /var/log/squid/access.log
|
||||||
|
volumeMounts:
|
||||||
|
- name: log-dir
|
||||||
|
mountPath: "/var/log/squid/"
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
|
@ -15,3 +15,5 @@ ports:
|
|||||||
#! External port where the proxy ends up exposed on localhost during tests. This value comes from
|
#! External port where the proxy ends up exposed on localhost during tests. This value comes from
|
||||||
#! our Kind configuration which maps 127.0.0.1:12346 to port 31235 on the Kind worker node.
|
#! our Kind configuration which maps 127.0.0.1:12346 to port 31235 on the Kind worker node.
|
||||||
local: 12346
|
local: 12346
|
||||||
|
|
||||||
|
supervisor_redirect_uri: ""
|
@ -34,8 +34,9 @@ import (
|
|||||||
func TestSupervisorLogin(t *testing.T) {
|
func TestSupervisorLogin(t *testing.T) {
|
||||||
env := library.IntegrationEnv(t)
|
env := library.IntegrationEnv(t)
|
||||||
|
|
||||||
// If anything in this test crashes, dump out the supervisor pod logs.
|
// If anything in this test crashes, dump out the supervisor and proxy pod logs.
|
||||||
defer library.DumpLogs(t, env.SupervisorNamespace)
|
defer library.DumpLogs(t, env.SupervisorNamespace, "")
|
||||||
|
defer library.DumpLogs(t, "dex", "app=proxy")
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -57,9 +58,13 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
TLSClientConfig: &tls.Config{RootCAs: ca.Pool()},
|
TLSClientConfig: &tls.Config{RootCAs: ca.Pool()},
|
||||||
Proxy: func(req *http.Request) (*url.URL, error) {
|
Proxy: func(req *http.Request) (*url.URL, error) {
|
||||||
if env.Proxy == "" {
|
if env.Proxy == "" {
|
||||||
|
t.Logf("passing request for %s with no proxy", req.URL)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return url.Parse(env.Proxy)
|
proxyURL, err := url.Parse(env.Proxy)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Logf("passing request for %s through proxy %s", req.URL, proxyURL.String())
|
||||||
|
return proxyURL, nil
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@ -106,7 +111,7 @@ func TestSupervisorLogin(t *testing.T) {
|
|||||||
assert.Eventually(t, func() bool {
|
assert.Eventually(t, func() bool {
|
||||||
discovery, err = oidc.NewProvider(oidc.ClientContext(ctx, httpClient), downstream.Spec.Issuer)
|
discovery, err = oidc.NewProvider(oidc.ClientContext(ctx, httpClient), downstream.Spec.Issuer)
|
||||||
return err == nil
|
return err == nil
|
||||||
}, 60*time.Second, 1*time.Second)
|
}, 30*time.Second, 200*time.Millisecond)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Start a callback server on localhost.
|
// Start a callback server on localhost.
|
||||||
|
@ -254,7 +254,7 @@ func CreateClientCredsSecret(t *testing.T, clientID string, clientSecret string)
|
|||||||
env := IntegrationEnv(t)
|
env := IntegrationEnv(t)
|
||||||
return CreateTestSecret(t,
|
return CreateTestSecret(t,
|
||||||
env.SupervisorNamespace,
|
env.SupervisorNamespace,
|
||||||
"test-client-creds-",
|
"test-client-creds",
|
||||||
"secrets.pinniped.dev/oidc-client",
|
"secrets.pinniped.dev/oidc-client",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"clientID": clientID,
|
"clientID": clientID,
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// DumpLogs is meant to be called in a `defer` to dump the logs of components in the cluster on a test failure.
|
// DumpLogs is meant to be called in a `defer` to dump the logs of components in the cluster on a test failure.
|
||||||
func DumpLogs(t *testing.T, namespace string) {
|
func DumpLogs(t *testing.T, namespace string, labelSelector string) {
|
||||||
// Only trigger on failed tests.
|
// Only trigger on failed tests.
|
||||||
if !t.Failed() {
|
if !t.Failed() {
|
||||||
return
|
return
|
||||||
@ -26,7 +26,7 @@ func DumpLogs(t *testing.T, namespace string) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
logTailLines := int64(40)
|
logTailLines := int64(40)
|
||||||
pods, err := kubeClient.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{})
|
pods, err := kubeClient.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{LabelSelector: labelSelector})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for _, pod := range pods.Items {
|
for _, pod := range pods.Items {
|
||||||
|
Loading…
Reference in New Issue
Block a user