Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: multi hydra #35

Merged
merged 25 commits into from Nov 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ad6042b
add redirect uris
paulbdavis Oct 30, 2019
01adc1f
revert go.mod and go.sum
paulbdavis Nov 5, 2019
4c27f10
add omitempty
paulbdavis Nov 5, 2019
7dd092a
clean up comment
paulbdavis Nov 5, 2019
5bf1445
add manager build to docker build
paulbdavis Nov 5, 2019
1787825
ignore manager binary
paulbdavis Nov 5, 2019
9b515b8
typo
paulbdavis Nov 5, 2019
3133f9a
modify regexp for redirect URI
paulbdavis Nov 6, 2019
4d7acb4
add test for invalid RedirectURI
paulbdavis Nov 6, 2019
ea303a0
add redirect URIs to other example config
paulbdavis Nov 6, 2019
858cf2e
add RedirectURIs to first test case in integration
paulbdavis Nov 6, 2019
1d10bff
allow specifying --forwarded-proto to add the X-Forwarded-Proto heade…
paulbdavis Nov 7, 2019
48fbbcd
change CRD version to v1alpha2
paulbdavis Nov 7, 2019
77a9e72
add hydra server definition to CRD
paulbdavis Nov 8, 2019
97610ea
Merge branch 'feature/x-forwarded-proto' into multi-hydra, add to CRD
paulbdavis Nov 8, 2019
4123613
add Hydra* props to CRD
paulbdavis Nov 8, 2019
13514e9
use another struct to make it actually optional
paulbdavis Nov 9, 2019
60f095f
make them actually optional (duh)
paulbdavis Nov 9, 2019
00d725e
check to return default quickly
paulbdavis Nov 9, 2019
b471ca1
use finalizer to delete oauth clients
paulbdavis Nov 11, 2019
70a33a4
image bump
paulbdavis Nov 11, 2019
ec3fdef
bump go version in go.mod for tests
paulbdavis Nov 12, 2019
205d1ec
change circleci settings for go 1.13
paulbdavis Nov 12, 2019
d5907a5
change api version back to v1alpha1
paulbdavis Nov 12, 2019
36d2f2b
fix installation of kustomize
paulbdavis Nov 12, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 7 additions & 7 deletions .circleci/config.yml
Expand Up @@ -2,11 +2,11 @@ version: 2
jobs:
build:
docker:
- image: circleci/golang:1.12
- image: circleci/golang:1.13
working_directory: /go/src/github.com/ory/hydra-maester
steps:
- run:
name: Enable go1.12 modules
name: Enable go1.11 modules
command: |
echo 'export GO111MODULE=on' >> $BASH_ENV
source $BASH_ENV
Expand All @@ -28,7 +28,7 @@ jobs:
- run: make
test:
docker:
- image: circleci/golang:1.12
- image: circleci/golang:1.13
environment:
- GO111MODULE=on
working_directory: /go/src/github.com/ory/hydra-maester
Expand Down Expand Up @@ -56,8 +56,8 @@ jobs:
name: Update golang
command: |
sudo rm -rf /usr/local/go/
curl -LO https://dl.google.com/go/go1.12.7.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.12.7.linux-amd64.tar.gz
curl -LO https://dl.google.com/go/go1.13.4.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.13.4.linux-amd64.tar.gz
sudo echo "export PATH=$PATH:/usr/local/go/bin" >> $HOME/.profile
go version

Expand All @@ -80,7 +80,7 @@ jobs:
command: |
go get github.com/onsi/ginkgo/ginkgo
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.0-beta.2
go install sigs.k8s.io/kustomize/v3/cmd/kustomize
go install sigs.k8s.io/kustomize/kustomize/v3

- run:
name: Install Kind
Expand All @@ -101,7 +101,7 @@ jobs:

release:
docker:
- image: circleci/golang:1.12
- image: circleci/golang:1.13
environment:
- GO111MODULE=on
working_directory: /go/src/github.com/ory/hydra-maester
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -23,4 +23,5 @@ bin
*.swo
*~

config/default/manager_image_patch.yaml-e
config/default/manager_image_patch.yaml-e
/manager
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -49,7 +49,7 @@ generate: controller-gen
$(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths=./api/...

# Build the docker image
docker-build: test
docker-build: test manager
docker build . -t ${IMG}
@echo "updating kustomize image patch file for manager resource"
sed -i'' -e 's@image: .*@image: '"${IMG}"'@' ./config/default/manager_image_patch.yaml
Expand Down
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -15,9 +15,9 @@
# Hydra-maester


This project contains a Kubernetes controller that uses Custom Resources (CR) to manage Hydra Oauth2 clients. ORY Hydra Maester watches for instances of `oauth2clients.oathkeeper.ory.sh/v1alpha1` CR and creates, updates, or deletes corresponding OAuth2 clients by communicating with ORY Hydra's API.
This project contains a Kubernetes controller that uses Custom Resources (CR) to manage Hydra Oauth2 clients. ORY Hydra Maester watches for instances of `oauth2clients.hydra.ory.sh/v1alpha1` CR and creates, updates, or deletes corresponding OAuth2 clients by communicating with ORY Hydra's API.

Visit Hydra-maester's [chart documentation](https://github.com/ory/k8s/blob/master/docs/helm/hydra-maester.md) and view [sample OAuth2 client resources](config/samples) to learn more about the `oauth2clients.oathkeeper.ory.sh/v1alpha1` CR.
Visit Hydra-maester's [chart documentation](https://github.com/ory/k8s/blob/master/docs/helm/hydra-maester.md) and view [sample OAuth2 client resources](config/samples) to learn more about the `oauth2clients.hydra.ory.sh/v1alpha1` CR.

The project is based on [Kubebuilder](https://github.com/kubernetes-sigs/kubebuilder).

Expand Down
62 changes: 58 additions & 4 deletions api/v1alpha1/oauth2client_types.go
Expand Up @@ -25,12 +25,46 @@ import (
type StatusCode string

const (
StatusRegistrationFailed StatusCode = "CLIENT_REGISTRATION_FAILED"
StatusCreateSecretFailed StatusCode = "SECRET_CREATION_FAILED"
StatusUpdateFailed StatusCode = "CLIENT_UPDATE_FAILED"
StatusInvalidSecret StatusCode = "INVALID_SECRET"
StatusRegistrationFailed StatusCode = "CLIENT_REGISTRATION_FAILED"
StatusCreateSecretFailed StatusCode = "SECRET_CREATION_FAILED"
StatusUpdateFailed StatusCode = "CLIENT_UPDATE_FAILED"
StatusInvalidSecret StatusCode = "INVALID_SECRET"
StatusInvalidHydraAddress StatusCode = "INVALID_HYDRA_ADDRESS"
)

// HydraAdmin defines the desired hydra admin instance to use for OAuth2Client
type HydraAdmin struct {
// +kubebuilder:validation:MaxLength=64
// +kubebuilder:validation:Pattern=(^$|^https?://.*)
//
// URL is the URL for the hydra instance on
// which to set up the client. This value will override the value
// provided to `--hydra-url`
URL string `json:"url,omitempty"`

// +kubebuilder:validation:Maximum=65535
//
// Port is the port for the hydra instance on
// which to set up the client. This value will override the value
// provided to `--hydra-port`
Port int `json:"port,omitempty"`

// +kubebuilder:validation:Pattern=(^$|^/.*)
//
// Endpoint is the endpoint for the hydra instance on which
// to set up the client. This value will override the value
// provided to `--endpoint` (defaults to `"/clients"` in the
// application)
Endpoint string `json:"endpoint,omitempty"`

// +kubebuilder:validation:Pattern=(^$|https?|off)
//
// ForwardedProto overrides the `--forwarded-proto` flag. The
// value "off" will force this to be off even if
// `--forwarded-proto` is specified
ForwardedProto string `json:"forwardedProto,omitempty"`
}

// OAuth2ClientSpec defines the desired state of OAuth2Client
type OAuth2ClientSpec struct {
// +kubebuilder:validation:MaxItems=4
Expand All @@ -46,6 +80,9 @@ type OAuth2ClientSpec struct {
// use at the authorization endpoint.
ResponseTypes []ResponseType `json:"responseTypes,omitempty"`

// RedirectURIs is an array of the redirect URIs allowed for the application
RedirectURIs []RedirectURI `json:"redirectUris,omitempty"`

// +kubebuilder:validation:Pattern=([a-zA-Z0-9\.\*]+\s?)+
//
// Scope is a string containing a space-separated list of scope values (as
Expand All @@ -59,6 +96,10 @@ type OAuth2ClientSpec struct {
//
// SecretName points to the K8s secret that contains this client's ID and password
SecretName string `json:"secretName"`

// HydraAdmin is the optional configuration to use for managing
// this client
HydraAdmin HydraAdmin `json:"hydraAdmin,omitempty"`
}

// +kubebuilder:validation:Enum=client_credentials;authorization_code;implicit;refresh_token
Expand All @@ -69,6 +110,10 @@ type GrantType string
// ResponseType represents an OAuth 2.0 response type strings
type ResponseType string

// +kubebuilder:validation:Pattern=\w+:/?/?[^\s]+
// RedirectURI represents a redirect URI for the client
type RedirectURI string

// OAuth2ClientStatus defines the observed state of OAuth2Client
type OAuth2ClientStatus struct {
// ObservedGeneration represents the most recent generation observed by the daemon set controller.
Expand Down Expand Up @@ -114,6 +159,7 @@ func (c *OAuth2Client) ToOAuth2ClientJSON() *hydra.OAuth2ClientJSON {
return &hydra.OAuth2ClientJSON{
GrantTypes: grantToStringSlice(c.Spec.GrantTypes),
ResponseTypes: responseToStringSlice(c.Spec.ResponseTypes),
RedirectURIs: redirectToStringSlice(c.Spec.RedirectURIs),
Scope: c.Spec.Scope,
Owner: fmt.Sprintf("%s/%s", c.Name, c.Namespace),
}
Expand All @@ -134,3 +180,11 @@ func grantToStringSlice(gt []GrantType) []string {
}
return output
}

func redirectToStringSlice(ru []RedirectURI) []string {
var output = make([]string, len(ru))
for i, elem := range ru {
output[i] = string(elem)
}
return output
}
42 changes: 37 additions & 5 deletions api/v1alpha1/oauth2client_types_test.go
Expand Up @@ -52,7 +52,7 @@ func TestCreateAPI(t *testing.T) {
Namespace: "default",
}

t.Run("by creating an API object if it meets CRD requirements", func(t *testing.T) {
t.Run("by creating an API object if it meets CRD requirements without optional parameters", func(t *testing.T) {

resetTestClient()

Expand All @@ -71,13 +71,45 @@ func TestCreateAPI(t *testing.T) {
require.Error(t, getErr)
})

t.Run("by creating an API object if it meets CRD requirements with optional parameters", func(t *testing.T) {

resetTestClient()

created.Spec.RedirectURIs = []RedirectURI{"https://client/account", "http://localhost:8080/account"}
created.Spec.HydraAdmin = HydraAdmin{
URL: "http://localhost",
Port: 4445,
// Endpoint: "/clients",
ForwardedProto: "https",
}

createErr = k8sClient.Create(context.TODO(), created)
require.NoError(t, createErr)

fetched = &OAuth2Client{}
getErr = k8sClient.Get(context.TODO(), key, fetched)
require.NoError(t, getErr)
assert.Equal(t, created, fetched)

deleteErr = k8sClient.Delete(context.TODO(), created)
require.NoError(t, deleteErr)

getErr = k8sClient.Get(context.TODO(), key, created)
require.Error(t, getErr)
})

t.Run("by failing if the requested object doesn't meet CRD requirements", func(t *testing.T) {

for desc, modifyClient := range map[string]func(){
"invalid grant type": func() { created.Spec.GrantTypes = []GrantType{"invalid"} },
"invalid response type": func() { created.Spec.ResponseTypes = []ResponseType{"invalid"} },
"invalid scope": func() { created.Spec.Scope = "" },
"missing secret name": func() { created.Spec.SecretName = "" },
"invalid grant type": func() { created.Spec.GrantTypes = []GrantType{"invalid"} },
"invalid response type": func() { created.Spec.ResponseTypes = []ResponseType{"invalid"} },
"invalid scope": func() { created.Spec.Scope = "" },
"missing secret name": func() { created.Spec.SecretName = "" },
"invalid redirect URI": func() { created.Spec.RedirectURIs = []RedirectURI{"invalid"} },
"invalid hydra url": func() { created.Spec.HydraAdmin.URL = "invalid" },
"invalid hydra port high": func() { created.Spec.HydraAdmin.Port = 65536 },
"invalid hydra endpoint": func() { created.Spec.HydraAdmin.Endpoint = "invalid" },
"invalid hydra forwarded proto": func() { created.Spec.HydraAdmin.Endpoint = "invalid" },
} {
t.Run(fmt.Sprintf("case=%s", desc), func(t *testing.T) {

Expand Down
21 changes: 21 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go
Expand Up @@ -23,6 +23,21 @@ import (
runtime "k8s.io/apimachinery/pkg/runtime"
)

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HydraAdmin) DeepCopyInto(out *HydraAdmin) {
*out = *in
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HydraAdmin.
func (in *HydraAdmin) DeepCopy() *HydraAdmin {
if in == nil {
return nil
}
out := new(HydraAdmin)
in.DeepCopyInto(out)
return out
}

// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OAuth2Client) DeepCopyInto(out *OAuth2Client) {
*out = *in
Expand Down Expand Up @@ -95,6 +110,12 @@ func (in *OAuth2ClientSpec) DeepCopyInto(out *OAuth2ClientSpec) {
*out = make([]ResponseType, len(*in))
copy(*out, *in)
}
if in.RedirectURIs != nil {
in, out := &in.RedirectURIs, &out.RedirectURIs
*out = make([]RedirectURI, len(*in))
copy(*out, *in)
}
out.HydraAdmin = in.HydraAdmin
}

// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAuth2ClientSpec.
Expand Down
37 changes: 37 additions & 0 deletions config/crd/bases/hydra.ory.sh_oauth2clients.yaml
Expand Up @@ -400,6 +400,43 @@ spec:
maxItems: 4
minItems: 1
type: array
hydraAdmin:
description: HydraAdmin is the optional configuration to use for managing
this client
properties:
endpoint:
description: Endpoint is the endpoint for the hydra instance on
which to set up the client. This value will override the value
provided to `--endpoint` (defaults to `"/clients"` in the application)
pattern: (^$|^/.*)
type: string
forwardedProto:
description: ForwardedProto overrides the `--forwarded-proto` flag.
The value "off" will force this to be off even if `--forwarded-proto`
is specified
pattern: (^$|https?|off)
type: string
port:
description: Port is the port for the hydra instance on which to
set up the client. This value will override the value provided
to `--hydra-port`
maximum: 65535
type: integer
url:
description: URL is the URL for the hydra instance on which to set
up the client. This value will override the value provided to
`--hydra-url`
maxLength: 64
pattern: (^$|^https?://.*)
type: string
type: object
redirectUris:
description: RedirectURIs is an array of the redirect URIs allowed for
the application
items:
pattern: \w+:/?/?[^\s]+
type: string
type: array
responseTypes:
description: ResponseTypes is an array of the OAuth 2.0 response type
strings that the client can use at the authorization endpoint.
Expand Down
2 changes: 1 addition & 1 deletion config/default/manager_image_patch.yaml
Expand Up @@ -8,5 +8,5 @@ spec:
spec:
containers:
# Change the value of image field below to your controller image URL
- image: controller:latest
- image: dangersalad/hydra-maester:v0.0.5-alpha15
name: manager
15 changes: 15 additions & 0 deletions config/samples/hydra_v1alpha1_oauth2client.yaml
Expand Up @@ -13,5 +13,20 @@ spec:
- id_token
- code
- token
redirectUris:
- https://client/account
- http://localhost:8080
scope: "read write"
secretName: my-secret-123
# these are optional
redirectUris:
- https://client/account
- http://localhost:8080
hydraAdmin:
# if hydraAdmin is specified, all of these fields are requried,
# but they can be empty/0
url: http://hydra-admin.namespace.cluster.domain
port: 4445
endpoint: /clients
forwardedProto: https

Expand Up @@ -8,7 +8,7 @@ data:
client_id: MDA5MDA5MDA=
client_secret: czNjUjM3cDRzc1ZWMHJEMTIzNA==
---
apiVersion: hydra.ory.sh/v1alpha1
apiVersion: hydra.ory.sh/v1alpha2
kind: OAuth2Client
metadata:
name: my-oauth2-client-2
Expand All @@ -25,3 +25,14 @@ spec:
- token
scope: "read write"
secretName: my-secret-456
# these are optional
redirectUris:
- https://client/account
- http://localhost:8080
hydraAdmin:
# if hydraAdmin is specified, all of these fields are requried,
# but they can be empty/0
url: http://hydra-admin.namespace.cluster.domain
port: 4445
endpoint: /clients
forwardedProto: https