Skip to content

Commit

Permalink
feat: TLS support for External Data Providers (#226)
Browse files Browse the repository at this point in the history
* feat: TLS support for External Data Providers

Signed-off-by: GitHub <noreply@github.com>

* Address PR comments

Signed-off-by: GitHub <noreply@github.com>

* nolint:gosec

Signed-off-by: GitHub <noreply@github.com>

* Address PR comments

Signed-off-by: GitHub <noreply@github.com>

* Add a flag to enable external data client auth

Signed-off-by: GitHub <noreply@github.com>

* Address PR comments

Signed-off-by: GitHub <noreply@github.com>

* Use sigs.k8s.io/controller-runtime/pkg/certwatcher

Signed-off-by: GitHub <noreply@github.com>

* Address PR comments

Signed-off-by: GitHub <noreply@github.com>
  • Loading branch information
Ernest Wong committed Jun 21, 2022
1 parent 36b73e1 commit a0dd2a5
Show file tree
Hide file tree
Showing 63 changed files with 9,938 additions and 24 deletions.
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 {
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

0 comments on commit a0dd2a5

Please sign in to comment.