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

feat: TLS support for External Data Providers #226

Merged
merged 8 commits into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ spec:
spec:
description: Spec defines the Provider specifications.
properties:
caBundle:
description: CABundle is a base64-encoded string that contains the
TLS CA bundle in PEM format. It is used to verify the signature
of the provider's certificate.
type: string
insecureTLSSkipVerify:
description: InsecureTLSSkipVerify skips the verification of Provider's
certificate if enabled.
type: boolean
timeout:
description: Timeout is the timeout when querying the provider.
type: integer
Expand Down
9 changes: 9 additions & 0 deletions constraint/deploy/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,15 @@ spec:
spec:
description: Spec defines the Provider specifications.
properties:
caBundle:
description: CABundle is a base64-encoded string that contains the
TLS CA bundle in PEM format. It is used to verify the signature
of the provider's certificate.
type: string
insecureTLSSkipVerify:
description: InsecureTLSSkipVerify skips the verification of Provider's
certificate if enabled.
type: boolean
timeout:
description: Timeout is the timeout when querying the provider.
type: integer
Expand Down
1 change: 1 addition & 0 deletions constraint/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ require (
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
Expand Down
5 changes: 5 additions & 0 deletions constraint/pkg/apis/externaldata/v1alpha1/provider_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ type ProviderSpec struct {
URL string `json:"url,omitempty"`
// Timeout is the timeout when querying the provider.
Timeout int `json:"timeout,omitempty"`
// CABundle is a base64-encoded string that contains the TLS CA bundle in PEM format.
// It is used to verify the signature of the provider's certificate.
CABundle string `json:"caBundle,omitempty"`
// InsecureTLSSkipVerify skips the verification of Provider's certificate if enabled.
InsecureTLSSkipVerify bool `json:"insecureTLSSkipVerify,omitempty"`
}

// +genclient
Expand Down
17 changes: 17 additions & 0 deletions constraint/pkg/client/drivers/local/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/open-policy-agent/opa/storage"
"github.com/open-policy-agent/opa/topdown/print"
opatypes "github.com/open-policy-agent/opa/types"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
)

type Arg func(*Driver) error
Expand Down Expand Up @@ -115,6 +116,22 @@ func DisableBuiltins(builtins ...string) Arg {
}
}

func AddExternalDataClientCertWatcher(clientCertWatcher *certwatcher.CertWatcher) Arg {
return func(d *Driver) error {
d.clientCertWatcher = clientCertWatcher

return nil
}
}

func EnableExternalDataClientAuth() Arg {
return func(d *Driver) error {
chewong marked this conversation as resolved.
Show resolved Hide resolved
d.enableExternalDataClientAuth = true

return nil
}
}

// Externs sets the fields under `data` that Rego in ConstraintTemplates
// can access. If unset, all fields can be accessed. Only fields recognized by
// the system can be enabled.
Expand Down
7 changes: 6 additions & 1 deletion constraint/pkg/client/drivers/local/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ func externalDataBuiltin(d *Driver) func(bctx rego.BuiltinContext, regorequest *
return externaldata.HandleError(http.StatusBadRequest, err)
}

externaldataResponse, statusCode, err := d.sendRequestToProvider(bctx.Context, &provider, regoReq.Keys)
clientCert, err := d.getTLSCertificate()
if err != nil {
return externaldata.HandleError(http.StatusBadRequest, err)
}

externaldataResponse, statusCode, err := d.sendRequestToProvider(bctx.Context, &provider, regoReq.Keys, clientCert)
if err != nil {
return externaldata.HandleError(statusCode, err)
}
Expand Down
21 changes: 21 additions & 0 deletions constraint/pkg/client/drivers/local/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package local
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"fmt"
"sort"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/open-policy-agent/opa/topdown/print"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
)

const (
Expand Down Expand Up @@ -61,6 +63,13 @@ type Driver struct {

// sendRequestToProvider allows Rego to send requests to the provider specified in external_data.
sendRequestToProvider externaldata.SendRequestToProvider

// enableExternalDataClientAuth enables the injection of a TLS certificate into an HTTP client
// that is used to communicate with providers.
enableExternalDataClientAuth bool

// clientCertWatcher is a watcher for the TLS certificate used to communicate with providers.
clientCertWatcher *certwatcher.CertWatcher
}

// AddTemplate adds templ to Driver. Normalizes modules into usable forms for
Expand Down Expand Up @@ -321,6 +330,18 @@ func (d *Driver) Dump(ctx context.Context) (string, error) {
return string(b), nil
}

func (d *Driver) getTLSCertificate() (*tls.Certificate, error) {
if !d.enableExternalDataClientAuth {
return nil, nil
}

if d.clientCertWatcher == nil {
return nil, fmt.Errorf("certWatcher should not be nil when enableExternalDataClientAuth is true")
}

return d.clientCertWatcher.GetCertificate(nil)
}

// rewriteModulePackage rewrites the module's package path to path.
func rewriteModulePackage(module *ast.Module) error {
pathParts := ast.Ref([]*ast.Term{ast.VarTerm(templatePath)})
Expand Down
Loading