From 1ea29cb2c24b44d15dffed3964e41e56b32da02d Mon Sep 17 00:00:00 2001 From: James Elliott Date: Sat, 22 Oct 2022 16:41:27 +1100 Subject: [PATCH] feat(storage): unix socket support (#4231) Support for unix sockets for MySQL and PostgreSQL. --- .../content/en/configuration/storage/mysql.md | 14 +- .../en/configuration/storage/postgres.md | 14 +- go.mod | 9 +- go.sum | 42 +---- internal/commands/helpers.go | 27 +++- internal/configuration/validator/session.go | 6 +- .../configuration/validator/session_test.go | 2 +- internal/storage/const.go | 3 +- .../storage/sql_provider_backend_mysql.go | 42 ++--- .../storage/sql_provider_backend_postgres.go | 149 +++++++++++++++--- 10 files changed, 205 insertions(+), 103 deletions(-) diff --git a/docs/content/en/configuration/storage/mysql.md b/docs/content/en/configuration/storage/mysql.md index a8ba2f64a..00fd9d1d8 100644 --- a/docs/content/en/configuration/storage/mysql.md +++ b/docs/content/en/configuration/storage/mysql.md @@ -55,12 +55,22 @@ See the [encryption_key docs](introduction.md#encryption_key). {{< confkey type="string" default="localhost" required="no" >}} -The database server host. +The database server host. This can also be a unix socket. If utilising an IPv6 literal address it must be enclosed by square brackets and quoted: ```yaml -host: "[fd00:1111:2222:3333::1]" +storage: + mysql: + host: "[fd00:1111:2222:3333::1]" +``` + +If utilizing a unix socket it must have the `unix:` prefix: + +```yaml +storage: + mysql: + host: /var/run/mysqld.sock ``` ### port diff --git a/docs/content/en/configuration/storage/postgres.md b/docs/content/en/configuration/storage/postgres.md index 3008c81fc..97aa701ef 100644 --- a/docs/content/en/configuration/storage/postgres.md +++ b/docs/content/en/configuration/storage/postgres.md @@ -57,12 +57,22 @@ See the [encryption_key docs](introduction.md#encryption_key). {{< confkey type="string" required="yes" >}} -The database server host. +The database server host. This can also be a unix socket. If utilising an IPv6 literal address it must be enclosed by square brackets and quoted: ```yaml -host: "[fd00:1111:2222:3333::1]" +storage: + postgres: + host: "[fd00:1111:2222:3333::1]" +``` + +If utilizing a unix socket it must have the `unix:` prefix: + +```yaml +storage: + postgres: + host: /var/run/postgres.sock ``` ### port diff --git a/go.mod b/go.mod index 3529a8b71..5af10b040 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.4.2 github.com/golang/mock v1.6.0 github.com/google/uuid v1.3.0 - github.com/jackc/pgx/v4 v4.17.2 + github.com/jackc/pgx/v5 v5.0.3 github.com/jmoiron/sqlx v1.3.5 github.com/knadh/koanf v1.4.4 github.com/mattn/go-sqlite3 v2.0.3+incompatible @@ -66,13 +66,8 @@ require ( github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect github.com/jandelgado/gcov2lcov v1.0.5 // indirect github.com/klauspost/compress v1.15.0 // indirect github.com/magiconair/properties v1.8.5 // indirect @@ -105,7 +100,7 @@ require ( github.com/ysmood/goob v0.4.0 // indirect github.com/ysmood/gson v0.7.1 // indirect github.com/ysmood/leakless v0.8.0 // indirect - golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect + golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/sys v0.1.0 // indirect diff --git a/go.sum b/go.sum index 4402cdf9f..befa3974d 100644 --- a/go.sum +++ b/go.sum @@ -44,11 +44,8 @@ github.com/DataDog/datadog-go v4.0.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/Gurpartap/logrus-stack v0.0.0-20170710170904-89c00d8a28f4 h1:vdT7QwBhJJEVNFMBNhRSFDRCB6O16T28VhvqRgqFyn8= github.com/Gurpartap/logrus-stack v0.0.0-20170710170904-89c00d8a28f4/go.mod h1:SvXOG8ElV28oAiG9zv91SDe5+9PfIr7PPccpr8YyXNs= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= @@ -133,7 +130,6 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= @@ -583,8 +579,6 @@ github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdK github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid/v3 v3.1.2/go.mod h1:xPwMqoocQ1L5G6pXX5BcE7N5jlzn2o19oqAKxwZW/kI= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -755,7 +749,6 @@ github.com/instana/go-sensor v1.29.0/go.mod h1:Uh9j3eF2mBw/FLk2MxISmVDIj8mtJBFRj github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65/go.mod h1:nYhEREG/B7HUY7P+LKOrqy53TpIqmJ9JyUShcaEKtGw= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= @@ -767,16 +760,8 @@ github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.6.0/go.mod h1:yeseQo4xhQbgyJs2c87RAXOH2i624N0Fh1KSPJya7qo= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 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/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= @@ -787,9 +772,6 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1: github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 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= @@ -801,9 +783,6 @@ github.com/jackc/pgtype v1.3.0/go.mod h1:b0JqxHvPmljG+HQ5IsvQ0yqeSi4nGcDTVjFoiLD github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= @@ -815,15 +794,13 @@ github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oA github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= +github.com/jackc/pgx/v5 v5.0.3 h1:4flM5ecR/555F0EcnjdaZa6MhBU+nr0QbZIo5vaKjuM= +github.com/jackc/pgx/v5 v5.0.3/go.mod h1:JBbvW3Hdw77jKl9uJrEDATUZIFM2VFPzRq4RWIhkF4o= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jandelgado/gcov2lcov v1.0.4-0.20210120124023-b83752c6dc08/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= github.com/jandelgado/gcov2lcov v1.0.4/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa346lVU0= @@ -889,6 +866,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= @@ -902,7 +880,6 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -1021,7 +998,6 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= -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/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -1205,6 +1181,7 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w= github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= @@ -1242,7 +1219,6 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= @@ -1490,13 +1466,10 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c= -golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1734,7 +1707,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -1972,8 +1944,8 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUy gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= diff --git a/internal/commands/helpers.go b/internal/commands/helpers.go index 01f23e8f8..0bfec419d 100644 --- a/internal/commands/helpers.go +++ b/internal/commands/helpers.go @@ -1,6 +1,8 @@ package commands import ( + "crypto/x509" + "github.com/authelia/authelia/v4/internal/authentication" "github.com/authelia/authelia/v4/internal/authorization" "github.com/authelia/authelia/v4/internal/metrics" @@ -17,11 +19,22 @@ import ( ) func getStorageProvider() (provider storage.Provider) { + switch { + case config.Storage.Local == nil: + return getStorageProviderWithPool(nil) + default: + caCertPool, _, _ := utils.NewX509CertPool(config.CertificatesDirectory) + + return getStorageProviderWithPool(caCertPool) + } +} + +func getStorageProviderWithPool(caCertPool *x509.CertPool) (provider storage.Provider) { switch { case config.Storage.PostgreSQL != nil: - return storage.NewPostgreSQLProvider(config) + return storage.NewPostgreSQLProvider(config, caCertPool) case config.Storage.MySQL != nil: - return storage.NewMySQLProvider(config) + return storage.NewMySQLProvider(config, caCertPool) case config.Storage.Local != nil: return storage.NewSQLiteProvider(config) default: @@ -31,12 +44,12 @@ func getStorageProvider() (provider storage.Provider) { func getProviders() (providers middlewares.Providers, warnings []error, errors []error) { // TODO: Adjust this so the CertPool can be used like a provider. - autheliaCertPool, warnings, errors := utils.NewX509CertPool(config.CertificatesDirectory) + caCertPool, warnings, errors := utils.NewX509CertPool(config.CertificatesDirectory) if len(warnings) != 0 || len(errors) != 0 { return providers, warnings, errors } - storageProvider := getStorageProvider() + storageProvider := getStorageProviderWithPool(caCertPool) var ( userProvider authentication.UserProvider @@ -47,7 +60,7 @@ func getProviders() (providers middlewares.Providers, warnings []error, errors [ case config.AuthenticationBackend.File != nil: userProvider = authentication.NewFileUserProvider(config.AuthenticationBackend.File) case config.AuthenticationBackend.LDAP != nil: - userProvider = authentication.NewLDAPUserProvider(config.AuthenticationBackend, autheliaCertPool) + userProvider = authentication.NewLDAPUserProvider(config.AuthenticationBackend, caCertPool) } templatesProvider, err := templates.New(templates.Config{EmailTemplatesPath: config.Notifier.TemplatePath}) @@ -59,7 +72,7 @@ func getProviders() (providers middlewares.Providers, warnings []error, errors [ switch { case config.Notifier.SMTP != nil: - notifier = notification.NewSMTPNotifier(config.Notifier.SMTP, autheliaCertPool, templatesProvider) + notifier = notification.NewSMTPNotifier(config.Notifier.SMTP, caCertPool, templatesProvider) case config.Notifier.FileSystem != nil: notifier = notification.NewFileNotifier(*config.Notifier.FileSystem) } @@ -68,7 +81,7 @@ func getProviders() (providers middlewares.Providers, warnings []error, errors [ clock := utils.RealClock{} authorizer := authorization.NewAuthorizer(config) - sessionProvider := session.NewProvider(config.Session, autheliaCertPool) + sessionProvider := session.NewProvider(config.Session, caCertPool) regulator := regulation.NewRegulator(config.Regulation, storageProvider, clock) oidcProvider, err := oidc.NewOpenIDConnectProvider(config.IdentityProviders.OIDC, storageProvider) diff --git a/internal/configuration/validator/session.go b/internal/configuration/validator/session.go index f39ab517b..7cf7a84b0 100644 --- a/internal/configuration/validator/session.go +++ b/internal/configuration/validator/session.go @@ -1,8 +1,8 @@ package validator import ( - "errors" "fmt" + "path" "strings" "github.com/authelia/authelia/v4/internal/configuration/schema" @@ -79,9 +79,7 @@ func validateRedis(config *schema.SessionConfiguration, validator *schema.Struct validateRedisCommon(config, validator) - if !strings.HasPrefix(config.Redis.Host, "/") && config.Redis.Port == 0 { - validator.Push(errors.New("A redis port different than 0 must be provided")) - } else if config.Redis.Port < 0 || config.Redis.Port > 65535 { + if !path.IsAbs(config.Redis.Host) && (config.Redis.Port < 1 || config.Redis.Port > 65535) { validator.Push(fmt.Errorf(errFmtSessionRedisPortRange, config.Redis.Port)) } diff --git a/internal/configuration/validator/session_test.go b/internal/configuration/validator/session_test.go index 6e4336e47..29ef3d91f 100644 --- a/internal/configuration/validator/session_test.go +++ b/internal/configuration/validator/session_test.go @@ -149,7 +149,7 @@ func TestShouldRaiseErrorWhenRedisHasHostnameButNoPort(t *testing.T) { assert.False(t, validator.HasWarnings()) assert.Len(t, validator.Errors(), 1) - assert.EqualError(t, validator.Errors()[0], "A redis port different than 0 must be provided") + assert.EqualError(t, validator.Errors()[0], "session: redis: option 'port' must be between 1 and 65535 but is configured as '0'") } func TestShouldRaiseOneErrorWhenRedisHighAvailabilityHasNodesWithNoHost(t *testing.T) { diff --git a/internal/storage/const.go b/internal/storage/const.go index 825caae04..39645979d 100644 --- a/internal/storage/const.go +++ b/internal/storage/const.go @@ -41,7 +41,8 @@ const ( ) const ( - sqlNetworkTypeTCP = "tcp" + sqlNetworkTypeTCP = "tcp" + sqlNetworkTypeUnixSocket = "unix" ) const ( diff --git a/internal/storage/sql_provider_backend_mysql.go b/internal/storage/sql_provider_backend_mysql.go index a336aeac9..b0382ed7d 100644 --- a/internal/storage/sql_provider_backend_mysql.go +++ b/internal/storage/sql_provider_backend_mysql.go @@ -1,11 +1,12 @@ package storage import ( + "crypto/x509" "fmt" + "path" "time" "github.com/go-sql-driver/mysql" - _ "github.com/go-sql-driver/mysql" // Load the MySQL Driver used in the connection string. "github.com/authelia/authelia/v4/internal/configuration/schema" ) @@ -16,9 +17,9 @@ type MySQLProvider struct { } // NewMySQLProvider a MySQL provider. -func NewMySQLProvider(config *schema.Configuration) (provider *MySQLProvider) { +func NewMySQLProvider(config *schema.Configuration, caCertPool *x509.CertPool) (provider *MySQLProvider) { provider = &MySQLProvider{ - SQLProvider: NewSQLProvider(config, providerMySQL, providerMySQL, dataSourceNameMySQL(*config.Storage.MySQL)), + SQLProvider: NewSQLProvider(config, providerMySQL, providerMySQL, dsnMySQL(config.Storage.MySQL)), } // All providers have differing SELECT existing table statements. @@ -30,32 +31,35 @@ func NewMySQLProvider(config *schema.Configuration) (provider *MySQLProvider) { return provider } -func dataSourceNameMySQL(config schema.MySQLStorageConfiguration) (dataSourceName string) { - dconfig := mysql.NewConfig() +func dsnMySQL(config *schema.MySQLStorageConfiguration) (dataSourceName string) { + dsnConfig := mysql.NewConfig() switch { + case path.IsAbs(config.Host): + dsnConfig.Net = sqlNetworkTypeUnixSocket + dsnConfig.Addr = config.Host case config.Port == 0: - dconfig.Net = sqlNetworkTypeTCP - dconfig.Addr = fmt.Sprintf("%s:%d", config.Host, 3306) + dsnConfig.Net = sqlNetworkTypeTCP + dsnConfig.Addr = fmt.Sprintf("%s:%d", config.Host, 3306) default: - dconfig.Net = sqlNetworkTypeTCP - dconfig.Addr = fmt.Sprintf("%s:%d", config.Host, config.Port) + dsnConfig.Net = sqlNetworkTypeTCP + dsnConfig.Addr = fmt.Sprintf("%s:%d", config.Host, config.Port) } switch config.Port { case 0: - dconfig.Addr = config.Host + dsnConfig.Addr = config.Host default: - dconfig.Addr = fmt.Sprintf("%s:%d", config.Host, config.Port) + dsnConfig.Addr = fmt.Sprintf("%s:%d", config.Host, config.Port) } - dconfig.DBName = config.Database - dconfig.User = config.Username - dconfig.Passwd = config.Password - dconfig.Timeout = config.Timeout - dconfig.MultiStatements = true - dconfig.ParseTime = true - dconfig.Loc = time.Local + dsnConfig.DBName = config.Database + dsnConfig.User = config.Username + dsnConfig.Passwd = config.Password + dsnConfig.Timeout = config.Timeout + dsnConfig.MultiStatements = true + dsnConfig.ParseTime = true + dsnConfig.Loc = time.Local - return dconfig.FormatDSN() + return dsnConfig.FormatDSN() } diff --git a/internal/storage/sql_provider_backend_postgres.go b/internal/storage/sql_provider_backend_postgres.go index 8a3ee7779..80f9929aa 100644 --- a/internal/storage/sql_provider_backend_postgres.go +++ b/internal/storage/sql_provider_backend_postgres.go @@ -1,11 +1,15 @@ package storage import ( + "crypto/tls" + "crypto/x509" + "errors" "fmt" - "strings" - "time" + "os" + "path" - _ "github.com/jackc/pgx/v4/stdlib" // Load the PostgreSQL Driver used in the connection string. + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/stdlib" "github.com/authelia/authelia/v4/internal/configuration/schema" ) @@ -16,9 +20,9 @@ type PostgreSQLProvider struct { } // NewPostgreSQLProvider a PostgreSQL provider. -func NewPostgreSQLProvider(config *schema.Configuration) (provider *PostgreSQLProvider) { +func NewPostgreSQLProvider(config *schema.Configuration, caCertPool *x509.CertPool) (provider *PostgreSQLProvider) { provider = &PostgreSQLProvider{ - SQLProvider: NewSQLProvider(config, providerPostgres, "pgx", dataSourceNamePostgreSQL(*config.Storage.PostgreSQL)), + SQLProvider: NewSQLProvider(config, providerPostgres, "pgx", dsnPostgreSQL(config.Storage.PostgreSQL, caCertPool)), } // All providers have differing SELECT existing table statements. @@ -128,33 +132,128 @@ func NewPostgreSQLProvider(config *schema.Configuration) (provider *PostgreSQLPr return provider } -func dataSourceNamePostgreSQL(config schema.PostgreSQLStorageConfiguration) (dataSourceName string) { - args := []string{ - fmt.Sprintf("host=%s", config.Host), - fmt.Sprintf("user='%s'", config.Username), - fmt.Sprintf("password='%s'", config.Password), - fmt.Sprintf("dbname=%s", config.Database), - fmt.Sprintf("search_path=%s", config.Schema), - fmt.Sprintf("sslmode=%s", config.SSL.Mode), +func dsnPostgreSQL(config *schema.PostgreSQLStorageConfiguration, globalCACertPool *x509.CertPool) (dsn string) { + dsnConfig, _ := pgx.ParseConfig("") + + ca, certs := loadPostgreSQLLegacyTLS(config) + + switch config.SSL.Mode { + case "disable": + break + default: + var caCertPool *x509.CertPool + + switch ca { + case nil: + caCertPool = globalCACertPool + default: + caCertPool = globalCACertPool.Clone() + caCertPool.AddCert(ca) + } + + dsnConfig.TLSConfig = &tls.Config{ + Certificates: certs, + RootCAs: caCertPool, + InsecureSkipVerify: true, //nolint:gosec + } + + switch { + case config.SSL.Mode == "require" && config.SSL.RootCertificate != "" || config.SSL.Mode == "verify-ca": + dsnConfig.TLSConfig.VerifyPeerCertificate = newPostgreSQLVerifyCAFunc(dsnConfig.TLSConfig) + case config.SSL.Mode == "verify-full": + dsnConfig.TLSConfig.InsecureSkipVerify = false + dsnConfig.TLSConfig.ServerName = config.Host + } } - if config.Port > 0 { - args = append(args, fmt.Sprintf("port=%d", config.Port)) + dsnConfig.Host = config.Host + dsnConfig.Port = uint16(config.Port) + dsnConfig.Database = config.Database + dsnConfig.User = config.Username + dsnConfig.Password = config.Password + dsnConfig.ConnectTimeout = config.Timeout + dsnConfig.RuntimeParams = map[string]string{ + "search_path": config.Schema, } + if dsnConfig.Port == 0 && !path.IsAbs(dsnConfig.Host) { + dsnConfig.Port = 4321 + } + + return stdlib.RegisterConnConfig(dsnConfig) +} + +func loadPostgreSQLLegacyTLS(config *schema.PostgreSQLStorageConfiguration) (ca *x509.Certificate, certs []tls.Certificate) { + var ( + err error + ) + if config.SSL.RootCertificate != "" { - args = append(args, fmt.Sprintf("sslrootcert=%s", config.SSL.RootCertificate)) + var caPEMBlock []byte + + if caPEMBlock, err = os.ReadFile(config.SSL.RootCertificate); err != nil { + return nil, nil + } + + if ca, err = x509.ParseCertificate(caPEMBlock); err != nil { + return nil, nil + } } - if config.SSL.Certificate != "" { - args = append(args, fmt.Sprintf("sslcert=%s", config.SSL.Certificate)) + if config.SSL.Certificate != "" && config.SSL.Key != "" { + var ( + keyPEMBlock []byte + certPEMBlock []byte + ) + + if keyPEMBlock, err = os.ReadFile(config.SSL.Key); err != nil { + return nil, nil + } + + if certPEMBlock, err = os.ReadFile(config.SSL.Certificate); err != nil { + return nil, nil + } + + var cert tls.Certificate + + if cert, err = tls.X509KeyPair(certPEMBlock, keyPEMBlock); err != nil { + return nil, nil + } + + certs = []tls.Certificate{cert} } - if config.SSL.Key != "" { - args = append(args, fmt.Sprintf("sslkey=%s", config.SSL.Key)) - } - - args = append(args, fmt.Sprintf("connect_timeout=%d", int32(config.Timeout/time.Second))) - - return strings.Join(args, " ") + return ca, certs +} + +func newPostgreSQLVerifyCAFunc(config *tls.Config) func(certificates [][]byte, _ [][]*x509.Certificate) (err error) { + return func(certificates [][]byte, _ [][]*x509.Certificate) (err error) { + certs := make([]*x509.Certificate, len(certificates)) + + var cert *x509.Certificate + + for i, asn1Data := range certificates { + if cert, err = x509.ParseCertificate(asn1Data); err != nil { + return errors.New("failed to parse certificate from server: " + err.Error()) + } + + certs[i] = cert + } + + // Leave DNSName empty to skip hostname verification. + opts := x509.VerifyOptions{ + Roots: config.RootCAs, + Intermediates: x509.NewCertPool(), + } + + // Skip the first cert because it's the leaf. All others + // are intermediates. + for _, cert = range certs[1:] { + opts.Intermediates.AddCert(cert) + } + + _, err = certs[0].Verify(opts) + + return err + } }