Skip to content

Commit

Permalink
feat: support to ory hydra running in secure mode (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
fjvierap authored May 10, 2021
1 parent 9d56503 commit 0ac5779
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 61 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ all: manager

# Run tests
test: generate fmt vet manifests
go test ./api/... ./controllers/... ./hydra/... -coverprofile cover.out
go test ./api/... ./controllers/... ./hydra/... ./helpers/... -coverprofile cover.out

# Run integration tests on local KIND cluster
# TODO: modify once integration tests have been implemented
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ To deploy the controller, edit the value of the ```--hydra-url``` argument in th

### Command-line flags

| Name | Required | Description | Default value | Example values |
|-----------------|----------|------------------------------|---------------|------------------------------------------------------|
| **hydra-url** | yes | ORY Hydra's service address | - | ` ory-hydra-admin.ory.svc.cluster.local` |
| **hydra-port** | no | ORY Hydra's service port | `4445` | `4445` |
| Name | Required | Description | Default value | Example values |
|----------------------------|----------|----------------------------------------|---------------|------------------------------------------------------|
| **hydra-url** | yes | ORY Hydra's service address | - | ` ory-hydra-admin.ory.svc.cluster.local` |
| **hydra-port** | no | ORY Hydra's service port | `4445` | `4445` |
| **tls-trust-store** | no | TLS cert path for hydra client | `""` | `/etc/ssl/certs/ca-certificates.crt` |
| **insecure-skip-verify** | no | Skip http client insecure verification | `false` | `true` or `false` |

## Development

Expand Down
20 changes: 9 additions & 11 deletions controllers/oauth2client_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ const (
FinalizerName = "finalizer.ory.hydra.sh"
)

type HydraClientMakerFunc func(hydrav1alpha1.OAuth2ClientSpec) (HydraClientInterface, error)

type clientMapKey struct {
url string
port int
Expand All @@ -56,10 +54,9 @@ type HydraClientInterface interface {

// OAuth2ClientReconciler reconciles a OAuth2Client object
type OAuth2ClientReconciler struct {
HydraClient HydraClientInterface
HydraClientMaker HydraClientMakerFunc
Log logr.Logger
otherClients map[clientMapKey]HydraClientInterface
HydraClient HydraClientInterface
Log logr.Logger
otherClients map[clientMapKey]HydraClientInterface
client.Client
}

Expand Down Expand Up @@ -332,10 +329,6 @@ func parseSecret(secret apiv1.Secret, authMethod hydrav1alpha1.TokenEndpointAuth

func (r *OAuth2ClientReconciler) getHydraClientForClient(oauth2client hydrav1alpha1.OAuth2Client) (HydraClientInterface, error) {
spec := oauth2client.Spec
if spec.HydraAdmin == (hydrav1alpha1.HydraAdmin{}) {
r.Log.Info(fmt.Sprintf("using default client"))
return r.HydraClient, nil
}
key := clientMapKey{
url: spec.HydraAdmin.URL,
port: spec.HydraAdmin.Port,
Expand All @@ -345,7 +338,12 @@ func (r *OAuth2ClientReconciler) getHydraClientForClient(oauth2client hydrav1alp
if c, ok := r.otherClients[key]; ok {
return c, nil
}
return r.HydraClientMaker(spec)
if r.HydraClient == nil {
return nil, errors.New("Not default client or other clients configured")
}
r.Log.Info(fmt.Sprintf("using default client"))
return r.HydraClient, nil

}

// Helper functions to check and remove string from a slice of strings.
Expand Down
3 changes: 0 additions & 3 deletions controllers/oauth2client_controller_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,6 @@ func getAPIReconciler(mgr ctrl.Manager, mock controllers.HydraClientInterface) r
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("OAuth2Client"),
HydraClient: mock,
HydraClientMaker: func(hydrav1alpha1.OAuth2ClientSpec) (controllers.HydraClientInterface, error) {
return mock, nil
},
}
}

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.15

require (
github.com/go-logr/logr v0.4.0
github.com/go-openapi/runtime v0.19.28
github.com/onsi/ginkgo v1.14.1
github.com/onsi/gomega v1.10.2
github.com/pkg/errors v0.9.1
Expand Down
140 changes: 140 additions & 0 deletions go.sum

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions helpers/http_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package helpers

import (
"crypto/tls"
"net/http"
"os"

ctrl "sigs.k8s.io/controller-runtime"

httptransport "github.com/go-openapi/runtime/client"
)

func CreateHttpClient(insecureSkipVerify bool, tlsTrustStore string) (*http.Client, error) {
setupLog := ctrl.Log.WithName("setup")
tr := &http.Transport{}
httpClient := &http.Client{}
if insecureSkipVerify {
setupLog.Info("configuring TLS with InsecureSkipVerify")
tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
httpClient.Transport = tr
}
if tlsTrustStore != "" {
if _, err := os.Stat(tlsTrustStore); err != nil {
return nil, err
}

setupLog.Info("configuring TLS with tlsTrustStore")
ops := httptransport.TLSClientOptions{
CA: tlsTrustStore,
InsecureSkipVerify: insecureSkipVerify,
}
if tlsClient, err := httptransport.TLSClient(ops); err != nil {
setupLog.Error(err, "Error while getting TLSClient, default http client will be used")
return tlsClient, nil
}
}
return httpClient, nil
}
41 changes: 41 additions & 0 deletions helpers/http_client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package helpers_test

import (
"io/ioutil"
"os"
"testing"

"github.com/ory/hydra-maester/helpers"

"github.com/stretchr/testify/require"
)

func TestCreateHttpClient(t *testing.T) {
t.Run("should create insecureSkipVerify client", func(t *testing.T) {
client, err := helpers.CreateHttpClient(true, "")
require.NotNil(t, client)
require.Nil(t, err)
})

t.Run("should create client with and tlsTrustStore", func(t *testing.T) {
file, err := ioutil.TempFile("/tmp", "test")
require.Nil(t, err)
client, err := helpers.CreateHttpClient(true, file.Name())
defer os.Remove(file.Name())
require.NotNil(t, client)
require.Nil(t, err)
})

t.Run("should not create client with and wrong tlsTrustStore", func(t *testing.T) {
client, err := helpers.CreateHttpClient(true, "/somefile")
require.Nil(t, client)
require.NotNil(t, err)
require.Equal(t, err.Error(), "stat /somefile: no such file or directory")
})

t.Run("should create client without and tlsTrustStore", func(t *testing.T) {
client, err := helpers.CreateHttpClient(true, "")
require.NotNil(t, client)
require.Nil(t, err)
})
}
79 changes: 37 additions & 42 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ package main
import (
"flag"
"fmt"
"net/http"
"net/url"
"os"
"time"

"github.com/ory/hydra-maester/helpers"

"github.com/ory/hydra-maester/hydra"

hydrav1alpha1 "github.com/ory/hydra-maester/api/v1alpha1"
Expand All @@ -49,19 +50,20 @@ func init() {

func main() {
var (
metricsAddr, hydraURL, endpoint, forwardedProto, syncPeriod string
hydraPort int
enableLeaderElection bool
metricsAddr, hydraURL, endpoint, forwardedProto, syncPeriod, tlsTrustStore string
hydraPort int
enableLeaderElection, insecureSkipVerify bool
)

flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&hydraURL, "hydra-url", "", "The address of ORY Hydra")
flag.IntVar(&hydraPort, "hydra-port", 4445, "Port ORY Hydra is listening on")
flag.StringVar(&endpoint, "endpoint", "/clients", "ORY Hydra's client endpoint")
flag.StringVar(&forwardedProto, "forwarded-proto", "", "If set, this adds the value as the X-Forwarded-Proto header in requests to the ORY Hydra admin server")
flag.StringVar(&tlsTrustStore, "tls-trust-store", "", "trust store certificate path. If set ca will be set in http client to connect with hydra admin")
flag.StringVar(&syncPeriod, "sync-period", "10h", "Determines the minimum frequency at which watched resources are reconciled")
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
flag.BoolVar(&insecureSkipVerify, "insecure-skip-verify", false, "If set, http client will be configured to skip insecure verification to connect with hydra admin")
flag.Parse()

ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
Expand Down Expand Up @@ -96,19 +98,24 @@ func main() {
ForwardedProto: forwardedProto,
},
}
hydraClientMaker := getHydraClientMaker(defaultSpec)
hydraClient, err := hydraClientMaker(defaultSpec)
if tlsTrustStore != "" {
if _, err := os.Stat(tlsTrustStore); err != nil {
setupLog.Error(err, "cannot parse tls trust store")
os.Exit(1)
}
}

hydraClient, err := getHydraClient(defaultSpec, tlsTrustStore, insecureSkipVerify)
if err != nil {
setupLog.Error(err, "making default hydra client", "controller", "OAuth2Client")
os.Exit(1)

}

err = (&controllers.OAuth2ClientReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("OAuth2Client"),
HydraClient: hydraClient,
HydraClientMaker: hydraClientMaker,
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("OAuth2Client"),
HydraClient: hydraClient,
}).SetupWithManager(mgr)
if err != nil {
setupLog.Error(err, "unable to create controller", "controller", "OAuth2Client")
Expand All @@ -123,39 +130,27 @@ func main() {
}
}

func getHydraClientMaker(defaultSpec hydrav1alpha1.OAuth2ClientSpec) controllers.HydraClientMakerFunc {

return controllers.HydraClientMakerFunc(func(spec hydrav1alpha1.OAuth2ClientSpec) (controllers.HydraClientInterface, error) {

if spec.HydraAdmin.URL == "" {
spec.HydraAdmin.URL = defaultSpec.HydraAdmin.URL
}
if spec.HydraAdmin.Port == 0 {
spec.HydraAdmin.Port = defaultSpec.HydraAdmin.Port
}
if spec.HydraAdmin.Endpoint == "" {
spec.HydraAdmin.Endpoint = defaultSpec.HydraAdmin.Endpoint
}
if spec.HydraAdmin.ForwardedProto == "" {
spec.HydraAdmin.ForwardedProto = defaultSpec.HydraAdmin.ForwardedProto
}
func getHydraClient(spec hydrav1alpha1.OAuth2ClientSpec, tlsTrustStore string, insecureSkipVerify bool) (controllers.HydraClientInterface, error) {

address := fmt.Sprintf("%s:%d", spec.HydraAdmin.URL, spec.HydraAdmin.Port)
u, err := url.Parse(address)
if err != nil {
return nil, fmt.Errorf("unable to parse ORY Hydra's URL: %w", err)
}
address := fmt.Sprintf("%s:%d", spec.HydraAdmin.URL, spec.HydraAdmin.Port)
u, err := url.Parse(address)
if err != nil {
return nil, err
}

client := &hydra.Client{
HydraURL: *u.ResolveReference(&url.URL{Path: spec.HydraAdmin.Endpoint}),
HTTPClient: &http.Client{},
}
c, err := helpers.CreateHttpClient(insecureSkipVerify, tlsTrustStore)
if err != nil {
return nil, err
}

if spec.HydraAdmin.ForwardedProto != "" && spec.HydraAdmin.ForwardedProto != "off" {
client.ForwardedProto = spec.HydraAdmin.ForwardedProto
}
client := &hydra.Client{
HydraURL: *u.ResolveReference(&url.URL{Path: spec.HydraAdmin.Endpoint}),
HTTPClient: c,
}

return client, nil
})
if spec.HydraAdmin.ForwardedProto != "" && spec.HydraAdmin.ForwardedProto != "off" {
client.ForwardedProto = spec.HydraAdmin.ForwardedProto
}

return client, nil
}

0 comments on commit 0ac5779

Please sign in to comment.