Skip to content

Commit 71d78bf

Browse files
committed
feat(postgresql): TLS options via Secret
Adds support for configuring TLS options using the credentials Secret. Very similar to how other providers are configured, this now also reads the `clusterCA`, `clientCert` and `clientKey` keys from the Secret. Integration tests are added, though they could be optimized to setup the PostgreSQL database only once and modify the configuration as needed to reduce the lenght of the tests, left as is for now.
1 parent 2e971b5 commit 71d78bf

File tree

13 files changed

+187
-38
lines changed

13 files changed

+187
-38
lines changed

cluster/local/postgresdb_functions.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,33 @@ EOF
137137
"${KUBECTL}" patch providers.pkg.crossplane.io/provider-sql --type=json --patch='[{"op":"add","path":"/spec/runtimeConfigRef","value":{"name":"postgres-tls"}}]'
138138
}
139139

140+
setup_provider_config_postgres_inline_tls() {
141+
echo_step "creating ProviderConfig for PostgresDb with inline TLS"
142+
local yaml="$(cat <<EOF
143+
---
144+
apiVersion: postgresql.sql.crossplane.io/v1alpha1
145+
kind: ProviderConfig
146+
metadata:
147+
name: default
148+
spec:
149+
credentials:
150+
source: PostgreSQLConnectionSecret
151+
connectionSecretRef:
152+
namespace: default
153+
name: postgresdb-creds
154+
EOF
155+
)"
156+
echo "${yaml}" | "${KUBECTL}" apply -f -
157+
158+
# make use of the default debug-config DeploymentRuntimeConfig
159+
"${KUBECTL}" patch providers.pkg.crossplane.io/provider-sql --type=json --patch='[{"op":"add","path":"/spec/runtimeConfigRef","value":{"name":"debug-config"}}]'
160+
161+
# add the clusterCA key from the postgresdb-postgresql-crt Secret created by
162+
# Helm chart to the postgresdb-creds Secret
163+
sslrootcert="$("${KUBECTL}" get secret postgresdb-postgresql-crt -o go-template='{{index .data "ca.crt"}}')"
164+
"${KUBECTL}" patch secret postgresdb-creds --type='json' --patch='[{"op" : "add" ,"path" : "/data/clusterCA" ,"value" : "'"${sslrootcert}"'"}]'
165+
}
166+
140167
setup_postgresdb_tests(){
141168
# install provider resources
142169
echo_step "creating PostgresDB Database resource"
@@ -306,6 +333,10 @@ delete_postgresdb_resources(){
306333

307334
# make sure to delete the PVC, otherwise the password will be reused from the first installation
308335
"${KUBECTL}" delete --ignore-not-found=true pvc data-postgresdb-postgresql-0
336+
337+
"${KUBECTL}" delete --ignore-not-found=true service postgres-nodeport
338+
339+
"${KUBECTL}" delete --ignore-not-found=true secret -n crossplane-system postgresdb-postgresql-crt
309340
}
310341

311342
integration_tests_postgres() {
@@ -329,4 +360,16 @@ integration_tests_postgres() {
329360
delete_postgresdb_resources
330361
}
331362
tls_tests
363+
364+
inline_tls_tests() {
365+
local PGSSLMODE=require
366+
setup_postgresdb_tls
367+
setup_provider_config_postgres_inline_tls
368+
check_tls_used
369+
setup_observe_only_database
370+
setup_postgresdb_tests
371+
check_all_roles_privileges
372+
delete_postgresdb_resources
373+
}
374+
inline_tls_tests
332375
}

pkg/clients/postgresql/postgresql.go

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"database/sql"
66
"errors"
77
"net/url"
8+
"os"
89

910
"github.com/crossplane-contrib/provider-sql/pkg/clients/xsql"
1011
"github.com/lib/pq"
@@ -55,17 +56,59 @@ func (o Options) queryString() string {
5556
return values.Encode()
5657
}
5758

59+
func (o *Options) withSecretData(data map[string][]byte) error {
60+
set := func(key string, to *string) error {
61+
v, ok := data[key]
62+
63+
if !ok {
64+
return nil
65+
}
66+
67+
f, err := os.CreateTemp("", key)
68+
if err != nil {
69+
return err
70+
}
71+
defer f.Close()
72+
73+
if _, err := f.Write(v); err != nil {
74+
return err
75+
}
76+
77+
*to = f.Name()
78+
79+
return nil
80+
}
81+
82+
if err := set(xpv1.ResourceCredentialsSecretClientCertKey, &o.SSLCert); err != nil {
83+
return err
84+
}
85+
86+
if err := set(xpv1.ResourceCredentialsSecretClientKeyKey, &o.SSLKey); err != nil {
87+
return err
88+
}
89+
90+
if err := set(xpv1.ResourceCredentialsSecretCAKey, &o.SSLRootCert); err != nil {
91+
return err
92+
}
93+
94+
return nil
95+
}
96+
5897
// New returns a new PostgreSQL database client. The default database name is
5998
// an empty string. The underlying pq library will default to either using the
6099
// value of PGDATABASE, or if unset, the hardcoded string 'postgres'.
61100
// The options provide additional settings to set up the connection for the
62101
// provider.
63-
func New(creds map[string][]byte, database string, options Options) xsql.DB {
102+
func New(data map[string][]byte, database string, options Options) (xsql.DB, error) {
64103
// TODO(negz): Support alternative connection secret formats?
65-
endpoint := string(creds[xpv1.ResourceCredentialsSecretEndpointKey])
66-
port := string(creds[xpv1.ResourceCredentialsSecretPortKey])
67-
username := string(creds[xpv1.ResourceCredentialsSecretUserKey])
68-
password := string(creds[xpv1.ResourceCredentialsSecretPasswordKey])
104+
endpoint := string(data[xpv1.ResourceCredentialsSecretEndpointKey])
105+
port := string(data[xpv1.ResourceCredentialsSecretPortKey])
106+
username := string(data[xpv1.ResourceCredentialsSecretUserKey])
107+
password := string(data[xpv1.ResourceCredentialsSecretPasswordKey])
108+
109+
if err := options.withSecretData(data); err != nil {
110+
return nil, err
111+
}
69112

70113
dsn := DSN(username, password, endpoint, port, database, options.queryString())
71114

@@ -74,7 +117,7 @@ func New(creds map[string][]byte, database string, options Options) xsql.DB {
74117
endpoint: endpoint,
75118
port: port,
76119
options: options,
77-
}
120+
}, nil
78121
}
79122

80123
// DSN returns the DSN URL

pkg/clients/postgresql/postgresql_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,27 @@
11
package postgresql
22

33
import (
4+
"os"
45
"testing"
6+
7+
v1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
8+
)
9+
10+
const (
11+
cert = `-----BEGIN CERTIFICATE-----
12+
MIIE/zCCAuegAwIBAgIUaQ2NqCCwap45bHpheQkI8ogei9wwDQYJKoZIhvcNAQEL
13+
nttUIJXC4NaaNY8xpwYBQF+Qm/Fkr68f2PbEQKp5MH1SI6U=
14+
-----END CERTIFICATE-----`
15+
16+
key = `-----BEGIN PRIVATE KEY-----
17+
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDBLPQTfvYTlFE1
18+
cX7ME/e2Dw2PsBiJYZaE7Nt/J1U5
19+
-----END PRIVATE KEY-----`
20+
21+
ca = `-----BEGIN CERTIFICATE-----
22+
MIIE+zCCAuOgAwIBAgIUSGfXbm4N5zBbvOo3tKJHMwxMu7YwDQYJKoZIhvcNAQEL
23+
tayuDzWN/5JRcsY3WSewY9kAzwLCXWzY9GzvBcRrPQ==
24+
-----END CERTIFICATE-----`
525
)
626

727
func TestDSNURLEscaping(t *testing.T) {
@@ -22,6 +42,16 @@ func TestDSNURLEscaping(t *testing.T) {
2242
}
2343

2444
func TestOptionsToQueryString(t *testing.T) {
45+
tmpdir := t.TempDir()
46+
os.Setenv("TMPDIR", tmpdir)
47+
48+
inline := Options{}
49+
inline.withSecretData(map[string][]byte{
50+
v1.ResourceCredentialsSecretClientCertKey: []byte(cert),
51+
v1.ResourceCredentialsSecretClientKeyKey: []byte(key),
52+
v1.ResourceCredentialsSecretCAKey: []byte(ca),
53+
})
54+
2555
cases := []struct {
2656
name string
2757
given Options

pkg/controller/postgresql/database/reconciler.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ import (
4545
)
4646

4747
const (
48-
errTrackPCUsage = "cannot track ProviderConfig usage"
49-
errGetPC = "cannot get ProviderConfig"
50-
errNoSecretRef = "ProviderConfig does not reference a credentials Secret"
51-
errGetSecret = "cannot get credentials Secret"
48+
errTrackPCUsage = "cannot track ProviderConfig usage"
49+
errGetPC = "cannot get ProviderConfig"
50+
errNoSecretRef = "ProviderConfig does not reference a credentials Secret"
51+
errGetSecret = "cannot get credentials Secret"
52+
errCreateConnection = "cannot configure connection"
5253

5354
errNotDatabase = "managed resource is not a Database custom resource"
5455
errSelectDB = "cannot select database"
@@ -92,7 +93,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error {
9293
type connector struct {
9394
kube client.Client
9495
usage resource.Tracker
95-
newDB func(creds map[string][]byte, database string, options postgresql.Options) xsql.DB
96+
newDB func(creds map[string][]byte, database string, options postgresql.Options) (xsql.DB, error)
9697
}
9798

9899
func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) {
@@ -125,7 +126,12 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
125126
return nil, errors.Wrap(err, errGetSecret)
126127
}
127128

128-
return &external{db: c.newDB(s.Data, pc.Spec.DefaultDatabase, pc.Spec.Options())}, nil
129+
db, err := c.newDB(s.Data, pc.Spec.DefaultDatabase, pc.Spec.Options())
130+
if err != nil {
131+
return nil, errors.Wrap(err, errCreateConnection)
132+
}
133+
134+
return &external{db}, nil
129135
}
130136

131137
type external struct{ db xsql.DB }

pkg/controller/postgresql/database/reconciler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestConnect(t *testing.T) {
6565
type fields struct {
6666
kube client.Client
6767
usage resource.Tracker
68-
newDB func(creds map[string][]byte, database string, options postgresql.Options) xsql.DB
68+
newDB func(creds map[string][]byte, database string, options postgresql.Options) (xsql.DB, error)
6969
}
7070

7171
type args struct {

pkg/controller/postgresql/extension/reconciler.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error {
8484
type connector struct {
8585
kube client.Client
8686
usage resource.Tracker
87-
newDB func(creds map[string][]byte, database string, options postgresql.Options) xsql.DB
87+
newDB func(creds map[string][]byte, database string, options postgresql.Options) (xsql.DB, error)
8888
}
8989

9090
func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) {
@@ -122,10 +122,18 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
122122
// We do not want to create an extension on the default DB
123123
// if the user was expecting a database name to be resolved.
124124
if cr.Spec.ForProvider.Database != nil {
125-
return &external{db: c.newDB(s.Data, *cr.Spec.ForProvider.Database, options)}, nil
125+
db, err := c.newDB(s.Data, *cr.Spec.ForProvider.Database, options)
126+
if err != nil {
127+
return nil, err
128+
}
129+
return &external{db}, nil
126130
}
127131

128-
return &external{db: c.newDB(s.Data, pc.Spec.DefaultDatabase, options)}, nil
132+
db, err := c.newDB(s.Data, pc.Spec.DefaultDatabase, options)
133+
if err != nil {
134+
return nil, err
135+
}
136+
return &external{db}, nil
129137
}
130138

131139
type external struct{ db xsql.DB }

pkg/controller/postgresql/extension/reconciler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestConnect(t *testing.T) {
6565
type fields struct {
6666
kube client.Client
6767
usage resource.Tracker
68-
newDB func(creds map[string][]byte, database string, options postgresql.Options) xsql.DB
68+
newDB func(creds map[string][]byte, database string, options postgresql.Options) (xsql.DB, error)
6969
}
7070

7171
type args struct {

pkg/controller/postgresql/grant/reconciler.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ import (
4242
)
4343

4444
const (
45-
errTrackPCUsage = "cannot track ProviderConfig usage"
46-
errGetPC = "cannot get ProviderConfig"
47-
errNoSecretRef = "ProviderConfig does not reference a credentials Secret"
48-
errGetSecret = "cannot get credentials Secret"
45+
errTrackPCUsage = "cannot track ProviderConfig usage"
46+
errGetPC = "cannot get ProviderConfig"
47+
errNoSecretRef = "ProviderConfig does not reference a credentials Secret"
48+
errGetSecret = "cannot get credentials Secret"
49+
errCreateConnection = "cannot configure connection"
4950

5051
errNotGrant = "managed resource is not a Grant custom resource"
5152
errSelectGrant = "cannot select grant"
@@ -93,7 +94,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error {
9394
type connector struct {
9495
kube client.Client
9596
usage resource.Tracker
96-
newDB func(creds map[string][]byte, database string, options postgresql.Options) xsql.DB
97+
newDB func(creds map[string][]byte, database string, options postgresql.Options) (xsql.DB, error)
9798
}
9899

99100
func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) {
@@ -125,8 +126,14 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
125126
if err := c.kube.Get(ctx, types.NamespacedName{Namespace: ref.Namespace, Name: ref.Name}, s); err != nil {
126127
return nil, errors.Wrap(err, errGetSecret)
127128
}
129+
130+
db, err := c.newDB(s.Data, pc.Spec.DefaultDatabase, pc.Spec.Options())
131+
if err != nil {
132+
return nil, errors.Wrap(err, errCreateConnection)
133+
}
134+
128135
return &external{
129-
db: c.newDB(s.Data, pc.Spec.DefaultDatabase, pc.Spec.Options()),
136+
db: db,
130137
kube: c.kube,
131138
}, nil
132139
}

pkg/controller/postgresql/grant/reconciler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func TestConnect(t *testing.T) {
7575
type fields struct {
7676
kube client.Client
7777
usage resource.Tracker
78-
newDB func(creds map[string][]byte, database string, options postgresql.Options) xsql.DB
78+
newDB func(creds map[string][]byte, database string, options postgresql.Options) (xsql.DB, error)
7979
}
8080

8181
type args struct {

pkg/controller/postgresql/role/reconciler.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ import (
4747
)
4848

4949
const (
50-
errTrackPCUsage = "cannot track ProviderConfig usage"
51-
errGetPC = "cannot get ProviderConfig"
52-
errNoSecretRef = "ProviderConfig does not reference a credentials Secret"
53-
errGetSecret = "cannot get credentials Secret"
50+
errTrackPCUsage = "cannot track ProviderConfig usage"
51+
errGetPC = "cannot get ProviderConfig"
52+
errNoSecretRef = "ProviderConfig does not reference a credentials Secret"
53+
errGetSecret = "cannot get credentials Secret"
54+
errCreateConnection = "cannot configure connection"
5455

5556
errNotRole = "managed resource is not a Role custom resource"
5657
errSelectRole = "cannot select role"
@@ -94,7 +95,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error {
9495
type connector struct {
9596
kube client.Client
9697
usage resource.Tracker
97-
newDB func(creds map[string][]byte, database string, options postgresql.Options) xsql.DB
98+
newDB func(creds map[string][]byte, database string, options postgresql.Options) (xsql.DB, error)
9899
}
99100

100101
func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) {
@@ -127,8 +128,13 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
127128
return nil, errors.Wrap(err, errGetSecret)
128129
}
129130

131+
db, err := c.newDB(s.Data, pc.Spec.DefaultDatabase, pc.Spec.Options())
132+
if err != nil {
133+
return nil, errors.Wrap(err, errCreateConnection)
134+
}
135+
130136
return &external{
131-
db: c.newDB(s.Data, pc.Spec.DefaultDatabase, pc.Spec.Options()),
137+
db: db,
132138
kube: c.kube,
133139
}, nil
134140
}

0 commit comments

Comments
 (0)