Skip to content

Commit eb34d26

Browse files
suhligvaleriap
authored andcommitted
Use client certs in backup and restore
[#160846440] Signed-off-by: Valeria Perticara <[email protected]> Signed-off-by: Steffen Uhlig <[email protected]>
1 parent 20ab873 commit eb34d26

File tree

9 files changed

+114
-49
lines changed

9 files changed

+114
-49
lines changed

jobs/bbr-postgres-db/spec

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ templates:
99
restore.sh.erb: bin/bbr/restore
1010
pgpass.erb: config/pgpass
1111
ca_cert.erb: config/ca_cert
12+
client_certificate.erb: config/client_certificate
13+
client_certificate_key.erb: config/client_certificate_key
1214

1315
packages:
1416
- postgres-common
@@ -28,3 +30,9 @@ properties:
2830
postgres.ssl_verify_hostname:
2931
default: true
3032
description: "If postgres is configured with a ca, setting this to 'true' changes sslmode to 'verify-full' rather than 'verify-ca'."
33+
postgres.client_certificate:
34+
default: ''
35+
description: "Client certificate. Specify it if you want to auhtenticate using certificates."
36+
postgres.client_certificate_key:
37+
default: ''
38+
description: "Secret key used for the client certificate. Specify it if you want to auhtenticate using certificates."

jobs/bbr-postgres-db/templates/backup.sh.erb

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,22 @@
11
#!/bin/bash
2-
<%
3-
sslmode = "prefer"
4-
if link("database").p("databases.tls.ca") != ''
5-
if p("postgres.ssl_verify_hostname")
6-
sslmode = "verify-full"
7-
else
8-
sslmode = "verify-ca"
9-
end
10-
end
11-
%>
122
set -euo pipefail
13-
source /var/vcap/jobs/bbr-postgres-db/config/config.sh
14-
15-
readonly PGPASSFILE="$(mktemp pgpass.XXXX)"
16-
readonly PGSSLMODE="<%=sslmode%>"
17-
readonly PGSSLROOTCERT="${JOB_DIR}/config/ca_cert"
18-
export PGPASSFILE
19-
export PGSSLMODE
20-
export PGSSLROOTCERT
213

224
doCleanup() {
235
rm ${PGPASSFILE}
6+
<% if p("postgres.client_certificate") != "" %>
7+
rm ${PGSSLKEY}
8+
<% end %>
249
}
2510

2611
trap doCleanup EXIT
2712

28-
cp $JOB_DIR/config/pgpass ${PGPASSFILE}
29-
chmod 0600 ${PGPASSFILE}
13+
source /var/vcap/jobs/bbr-postgres-db/config/config.sh
14+
15+
export_as_private_temp_file "$JOB_DIR/config/pgpass" PGPASSFILE
16+
17+
<% if p("postgres.client_certificate") != "" %>
18+
export_as_private_temp_file "$JOB_DIR/config/client_certificate_key" PGSSLKEY
19+
<% end %>
3020

3121
for dbname in ${DATABASES[@]}; do
3222
BBR_ARTIFACT_FILE_PATH="${BBR_ARTIFACT_DIRECTORY}/postgres_${dbname}.sql"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<%=p("postgres.client_certificate")%>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<%=p("postgres.client_certificate_key")%>

jobs/bbr-postgres-db/templates/config.sh.erb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ if_link("database") do |data|
55
if p("postgres.dbuser") != "vcap"
66
dbhost = data.address
77
end
8+
end
9+
sslmode = "prefer"
10+
if link("database").p("databases.tls.ca") != ''
11+
if p("postgres.ssl_verify_hostname")
12+
sslmode = "verify-full"
13+
else
14+
sslmode = "verify-ca"
15+
end
816
end
917
%>
1018
current_version="9.6.10"
@@ -13,3 +21,22 @@ PACKAGE_DIR="/var/vcap/packages/postgres-${current_version}"
1321
PORT="<%= link("database").p("databases.port") %>"
1422
DATABASES=(<%= link("database").p("databases.databases", []).map{|d| d["name"]}.join(' ')%>)
1523
DBHOST=<%= dbhost %>
24+
25+
readonly PGSSLMODE="<%=sslmode%>"
26+
readonly PGSSLROOTCERT="${JOB_DIR}/config/ca_cert"
27+
export PGSSLMODE
28+
export PGSSLROOTCERT
29+
<% if p("postgres.client_certificate") != "" %>
30+
readonly PGSSLCERT="${JOB_DIR}/config/client_certificate"
31+
export PGSSLCERT
32+
<% end %>
33+
34+
export_as_private_temp_file() {
35+
local source=$1
36+
local target=$2
37+
38+
local readonly PGENVVAR="$(mktemp pgenv.XXXX)"
39+
cp $source ${PGENVVAR}
40+
chmod 0600 ${PGENVVAR}
41+
eval "export $target=$PGENVVAR"
42+
}

jobs/bbr-postgres-db/templates/pgpass.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
link("database").if_p("databases.roles") do |roles|
55
roles.each do |role|
66
if role["name"] == dbuser
7-
if role["password"].to_s.empty?
8-
raise "Password is required for postgres.dbuser '#{dbuser}'"
7+
if role["password"].to_s.empty? and p("postgres.client_certificate") == ""
8+
raise "Password or client certificate is required for postgres.dbuser '#{dbuser}'"
99
end
1010
password = role["password"].to_s
1111
end

jobs/bbr-postgres-db/templates/restore.sh.erb

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,27 @@
11
#!/bin/bash
22
set -euo pipefail
3-
source /var/vcap/jobs/bbr-postgres-db/config/config.sh
4-
<%
5-
sslmode = "prefer"
6-
if link("database").p("databases.tls.ca") != ''
7-
if p("postgres.ssl_verify_hostname")
8-
sslmode = "verify-full"
9-
else
10-
sslmode = "verify-ca"
11-
end
12-
end
13-
%>
14-
15-
readonly TMP_LIST_FILE="$(mktemp restore.postgres.XXXX)"
16-
readonly PGPASSFILE="$(mktemp pgpass.XXXX)"
17-
readonly PGSSLMODE="<%=sslmode%>"
18-
readonly PGSSLROOTCERT="${JOB_DIR}/config/ca_cert"
19-
export PGPASSFILE
20-
export PGSSLMODE
21-
export PGSSLROOTCERT
223

234
doCleanup() {
245
rm ${PGPASSFILE}
6+
<% if p("postgres.client_certificate") != "" %>
7+
rm ${PGSSLKEY}
8+
<% end %>
259
if [ -f "${TMP_LIST_FILE}" ]; then
2610
rm "${TMP_LIST_FILE}"
2711
fi
2812
}
2913

3014
trap doCleanup EXIT
3115

32-
cp $JOB_DIR/config/pgpass ${PGPASSFILE}
33-
chmod 0600 ${PGPASSFILE}
16+
source /var/vcap/jobs/bbr-postgres-db/config/config.sh
17+
18+
readonly TMP_LIST_FILE="$(mktemp restore.postgres.XXXX)"
19+
20+
export_as_private_temp_file "$JOB_DIR/config/pgpass" PGPASSFILE
21+
22+
<% if p("postgres.client_certificate") != "" %>
23+
export_as_private_temp_file "$JOB_DIR/config/client_certificate_key" PGSSLKEY
24+
<% end %>
3425

3526
for dbname in ${DATABASES[@]}; do
3627
BBR_ARTIFACT_FILE_PATH="${BBR_ARTIFACT_DIRECTORY}/postgres_${dbname}.sql"

src/acceptance-tests/deploy/backup_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@ var _ = Describe("Backup and restore a deployment", func() {
169169

170170
It("Successfully backup and restore the database", AssertBackupRestoreSuccessful())
171171
})
172+
173+
Context("With SSL authentication", func() {
174+
BeforeEach(func() {
175+
deployHelper.SetOpDefs(helpers.Define_bbr_client_certs())
176+
})
177+
178+
It("Successfully backup and restore the database", AssertBackupRestoreSuccessful())
179+
})
172180
})
173181
})
174182
})

src/acceptance-tests/testing/helpers/op_defs_utilities.go

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,10 @@ func Define_bbr_not_colocated_ops() []OpDefinition {
5050

5151
func Define_bbr_ssl_verify_full() []OpDefinition {
5252
var ops []OpDefinition
53-
var value interface{}
54-
var path string
5553

5654
ops = Define_bbr_not_colocated_ops()
5755
ops = append(ops, Define_ssl_ops()...)
5856

59-
path = "/instance_groups/name=backup/jobs/name=bbr-postgres-db/properties/postgres?/ca"
60-
value = "((postgres_cert.ca))"
61-
AddOpDefinition(&ops, "replace", path, value)
62-
6357
return ops
6458
}
6559

@@ -77,6 +71,51 @@ func Define_bbr_ssl_verify_ca() []OpDefinition {
7771
return ops
7872
}
7973

74+
func Define_bbr_client_certs() []OpDefinition {
75+
var ops []OpDefinition
76+
var value interface{}
77+
var path string
78+
79+
bbruser := "bbruser"
80+
81+
ops = Define_bbr_not_colocated_ops()
82+
ops = append(ops, Define_mutual_ssl_ops()...)
83+
84+
path = "/instance_groups/name=backup/jobs/name=bbr-postgres-db/properties/postgres?/client_certificate"
85+
value = "((bbr_user_certs.certificate))"
86+
AddOpDefinition(&ops, "replace", path, value)
87+
88+
path = "/instance_groups/name=backup/jobs/name=bbr-postgres-db/properties/postgres?/client_certificate_key"
89+
value = "((bbr_user_certs.private_key))"
90+
AddOpDefinition(&ops, "replace", path, value)
91+
92+
path = "/variables?/name=bbr_user_certs?"
93+
value = map[interface{}]interface{}{
94+
"name": "bbr_user_certs",
95+
"type": "certificate",
96+
"options": map[interface{}]interface{}{
97+
"ca": "postgres_ca",
98+
"common_name": bbruser,
99+
"alternative_names": []interface{}{},
100+
"extended_key_usage": []interface{}{"server_auth", "client_auth"},
101+
},
102+
}
103+
AddOpDefinition(&ops, "replace", path, value)
104+
105+
path = "/instance_groups/name=postgres/jobs/name=postgres/properties/databases/roles?/name=bbruser?"
106+
value = map[interface{}]interface{}{
107+
"name": bbruser,
108+
"permissions": []interface{}{"SUPERUSER"},
109+
}
110+
AddOpDefinition(&ops, "replace", path, value)
111+
112+
path = "/instance_groups/name=backup/jobs/name=bbr-postgres-db/properties/postgres?/dbuser"
113+
value = bbruser
114+
AddOpDefinition(&ops, "replace", path, value)
115+
116+
return ops
117+
}
118+
80119
func Define_upgrade_no_copy_ops() []OpDefinition {
81120
var ops []OpDefinition
82121
var value interface{}

0 commit comments

Comments
 (0)