Skip to content

Commit

Permalink
feat(collectors): Add TLS parameters to the postgres collector (#875)
Browse files Browse the repository at this point in the history
For a postgres collector spec targeting a server configured to accept
(m)TLS connections we need to pass in the necessary parameters in order
to successfully connect to the server. Both preflight and support bundle
specs use this collector.

This change allows us to pass in the necessary TLS parameters via inlined
TLS configuration or via a secret reference.

Fixes #747
  • Loading branch information
banjoh authored Nov 30, 2022
1 parent c85bf9a commit 2a61a86
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 11 deletions.
1 change: 0 additions & 1 deletion examples/preflight/postgres.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@ spec:
message: The postgres server must be at least version 10
- pass:
message: The postgres connection checks out

4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ require (
github.com/gorilla/handlers v1.5.1
github.com/hashicorp/go-getter v1.6.2
github.com/hashicorp/go-multierror v1.1.1
github.com/lib/pq v1.10.7
github.com/jackc/pgx/v5 v5.1.1
github.com/longhorn/go-iscsi-helper v0.0.0-20210330030558-49a327fb024e
github.com/manifoldco/promptui v0.9.0
github.com/mattn/go-isatty v0.0.16
Expand Down Expand Up @@ -54,6 +54,8 @@ require (
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
github.com/googleapis/go-type-adapters v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/mistifyio/go-zfs/v3 v3.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sylabs/sif/v2 v2.8.1 // indirect
Expand Down
13 changes: 8 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,12 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgx/v5 v5.1.1 h1:pZD79K1SYv8wc2HmCQA6VdmRQi7/OtCfv9bM3WAXUYA=
github.com/jackc/pgx/v5 v5.1.1/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
Expand Down Expand Up @@ -711,8 +717,6 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
Expand Down Expand Up @@ -803,7 +807,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
Expand Down Expand Up @@ -1092,7 +1095,7 @@ go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee33
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
Expand Down Expand Up @@ -1666,8 +1669,8 @@ gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
Expand Down
46 changes: 42 additions & 4 deletions pkg/collect/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ package collect
import (
"bytes"
"context"
"database/sql"
"encoding/json"
"fmt"
"regexp"

_ "github.com/lib/pq"
"github.com/jackc/pgx/v5"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"k8s.io/client-go/kubernetes"
Expand All @@ -33,15 +32,54 @@ func (c *CollectPostgres) IsExcluded() (bool, error) {
return isExcluded(c.Collector.Exclude)
}

func (c *CollectPostgres) createConnectConfig() (*pgx.ConnConfig, error) {
if c.Collector.URI == "" {
return nil, errors.New("postgres uri cannot be empty")
}

cfg, err := pgx.ParseConfig(c.Collector.URI)
if err != nil {
return nil, errors.Wrap(err, "failed to parse postgres config")
}

if c.Collector.TLS != nil {
tlsCfg, err := createTLSConfig(c.Context, c.Client, c.Collector.TLS)
if err != nil {
return nil, err
}

tlsCfg.ServerName = cfg.Host
cfg.TLSConfig = tlsCfg
}

return cfg, nil
}

func (c *CollectPostgres) connect() (*pgx.Conn, error) {
connCfg, err := c.createConnectConfig()
if err != nil {
return nil, err
}

conn, err := pgx.ConnectConfig(c.Context, connCfg)
if err != nil {
return nil, err
}

return conn, nil
}

func (c *CollectPostgres) Collect(progressChan chan<- interface{}) (CollectorResult, error) {
databaseConnection := DatabaseConnection{}

db, err := sql.Open("postgres", c.Collector.URI)
conn, err := c.connect()
if err != nil {
databaseConnection.Error = err.Error()
} else {
defer conn.Close(c.Context)

query := `select version()`
row := db.QueryRow(query)
row := conn.QueryRow(c.Context, query)
version := ""
if err := row.Scan(&version); err != nil {
databaseConnection.Error = err.Error()
Expand Down
72 changes: 72 additions & 0 deletions pkg/collect/postgres_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package collect

import (
"context"
"testing"

"github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
testclient "k8s.io/client-go/kubernetes/fake"
)

func Test_parsePostgresVersion(t *testing.T) {
Expand Down Expand Up @@ -44,3 +47,72 @@ func Test_parsePostgresVersion(t *testing.T) {
})
}
}

func TestCollectPostgres_createConnectConfigPlainText(t *testing.T) {
tests := []struct {
name string
uri string
hasError bool
}{
{
name: "valid uri creates postgres connection config successfully",
uri: "postgresql://user:password@my-pghost:5432/defaultdb?sslmode=require",
},
{
name: "empty uri fails to create postgres connection config with error",
uri: "",
hasError: true,
},
{
name: "invalid redis protocol fails to create postgres connection config with error",
uri: "http://somehost:5432",
hasError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &CollectPostgres{
Context: context.Background(),
Collector: &v1beta2.Database{
URI: tt.uri,
},
}

connCfg, err := c.createConnectConfig()
assert.Equal(t, err != nil, tt.hasError)
if err == nil {
require.NotNil(t, connCfg)
assert.Equal(t, connCfg.Host, "my-pghost")
assert.Equal(t, connCfg.Database, "defaultdb")
} else {
t.Log(err)
assert.Nil(t, connCfg)
}
})
}
}

func TestCollectPostgres_createConnectConfigTLS(t *testing.T) {
k8sClient := testclient.NewSimpleClientset()

c := &CollectPostgres{
Client: k8sClient,
Context: context.Background(),
Collector: &v1beta2.Database{
URI: "postgresql://user:password@my-pghost:5432/defaultdb?sslmode=require",
TLS: &v1beta2.TLSParams{
CACert: getTestFixture(t, "db/ca.pem"),
ClientCert: getTestFixture(t, "db/client.pem"),
ClientKey: getTestFixture(t, "db/client-key.pem"),
},
},
}

connCfg, err := c.createConnectConfig()
assert.NoError(t, err)
assert.NotNil(t, connCfg)
assert.Equal(t, connCfg.Host, "my-pghost")
assert.NotNil(t, connCfg.TLSConfig.Certificates)
assert.NotNil(t, connCfg.TLSConfig.RootCAs)
assert.False(t, connCfg.TLSConfig.InsecureSkipVerify)
}

0 comments on commit 2a61a86

Please sign in to comment.