From 5a3ea0f895657ee9923e9ada389e618e7f4075c0 Mon Sep 17 00:00:00 2001 From: JT Olio Date: Thu, 30 May 2024 11:51:40 -0400 Subject: [PATCH] pkg/server, cmd/linksharing: support specifying uplink client identities this change allows the gateway and linksharing processes to specify stable uplink client identities. this is important so that different gateway regions can get different choice-of-two load balancing profiles, and other benefits of satellite-trusted uplinks. we intend that all gateways and linksharing services within a single region use the same identity. note that the linksharing process already has an identity called the TierServiceIdentity, where it asks the Satellite for tier services using that identity. If that identity is also different between regions and the same within a region, it is fine to reuse that identity for this as part of the configuration. a future patch set could simplify the configuration so only one is necessary to configure Change-Id: If2942af0907126d1c91578d61af6cad43c13c69b --- cmd/gateway-mt/config.yaml.lock | 6 ++++++ cmd/linksharing/config.yaml.lock | 6 ++++++ cmd/linksharing/main.go | 12 +++++++++++ go.mod | 2 +- go.sum | 4 ++-- pkg/server/config.go | 2 ++ pkg/server/server.go | 15 ++++++++++--- pkg/uplinkutil/config.go | 37 ++++++++++++++++++++++++++++++++ testsuite/go.mod | 2 +- testsuite/go.sum | 4 ++-- 10 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 pkg/uplinkutil/config.go diff --git a/cmd/gateway-mt/config.yaml.lock b/cmd/gateway-mt/config.yaml.lock index 0e78a8fe..c0c6da5b 100644 --- a/cmd/gateway-mt/config.yaml.lock +++ b/cmd/gateway-mt/config.yaml.lock @@ -55,6 +55,12 @@ cert-magic.staging: false # timeout for dials # client.dial-timeout: 10s +# path to the certificate chain for this identity +client.identity.cert-path: "" + +# path to the private key for this identity +client.identity.key-path: "" + # maximum buffer size for DRPC streams # client.maximum-buffer-size: 304.00 KB diff --git a/cmd/linksharing/config.yaml.lock b/cmd/linksharing/config.yaml.lock index f2cec718..969372f6 100644 --- a/cmd/linksharing/config.yaml.lock +++ b/cmd/linksharing/config.yaml.lock @@ -64,6 +64,12 @@ cert-magic.tier-service-identity.key-path: /identity.key # list of clients IPs (comma separated) which are trusted; usually used when the service run behinds gateways, load balancers, etc. client-trusted-ips-list: [] +# path to the certificate chain for this identity +client.identity.cert-path: "" + +# path to the private key for this identity +client.identity.key-path: "" + # RPC connection pool capacity connection-pool.capacity: 100 diff --git a/cmd/linksharing/main.go b/cmd/linksharing/main.go index 9cb7f104..ed3c1402 100644 --- a/cmd/linksharing/main.go +++ b/cmd/linksharing/main.go @@ -25,6 +25,7 @@ import ( "storj.io/edge/pkg/linksharing" "storj.io/edge/pkg/linksharing/sharing" "storj.io/edge/pkg/linksharing/sharing/assets" + "storj.io/edge/pkg/uplinkutil" "storj.io/uplink" ) @@ -53,6 +54,10 @@ type LinkSharing struct { ListPageLimit int `help:"maximum number of paths to list on a single page" default:"100"` DynamicAssetsDir string `help:"use a assets dir that is reparsed for every request" default:""` + Client struct { + Identity uplinkutil.IdentityConfig + } + SatelliteConnectionPool satelliteConnectionPoolConfig ConnectionPool connectionPoolConfig @@ -148,6 +153,11 @@ func cmdRun(cmd *cobra.Command, args []string) (err error) { dynamicAssets = true } + clientCertPEM, clientKeyPEM, err := runCfg.Client.Identity.LoadPEMs() + if err != nil { + return err + } + var tlsConfig *httpserver.TLSConfig if !runCfg.InsecureDisableTLS { tlsConfig = &httpserver.TLSConfig{ @@ -197,6 +207,8 @@ func cmdRun(cmd *cobra.Command, args []string) (err error) { Uplink: &uplink.Config{ UserAgent: "linksharing", DialTimeout: runCfg.DialTimeout, + ChainPEM: clientCertPEM, + KeyPEM: clientKeyPEM, }, ListPageLimit: runCfg.ListPageLimit, }, diff --git a/go.mod b/go.mod index be6e97d3..d4b0a6cb 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( storj.io/eventkit v0.0.0-20240415002644-1d9596fee086 storj.io/gateway v1.9.1-0.20240517132048-2aaa6fd6d33e storj.io/minio v0.0.0-20240517005305-6bf61e2db47a - storj.io/uplink v1.13.0 + storj.io/uplink v1.13.1-0.20240522144333-931e862e9315 storj.io/zipper v0.0.0-20220124122551-2ac2d53a46f6 ) diff --git a/go.sum b/go.sum index d8fab62b..cb50c810 100644 --- a/go.sum +++ b/go.sum @@ -1815,7 +1815,7 @@ storj.io/monkit-jaeger v0.0.0-20240221095020-52b0792fa6cd/go.mod h1:nwyyJiAFAPRu storj.io/picobuf v0.0.3 h1:xAUPB5ZUGfxkqd3bnw3zp01kkWb9wlhg4vtZWUs2S9A= storj.io/picobuf v0.0.3/go.mod h1:4V4xelV1RSCck5GgmkL/Txw9l6IfX3XcBzegmL5Kudo= storj.io/uplink v1.7.1/go.mod h1:pKqsMpNMIAz//2TXzUGOR6tpu3iyabvXV4VWINj4jaY= -storj.io/uplink v1.13.0 h1:MAwzMaO4F86n2sMdNm7/m7LVyf8KD0FP+72h1H+HuRE= -storj.io/uplink v1.13.0/go.mod h1:MT8+V7qddgn1ra09piq3Idy4IUva2S90S7me7U8n6cE= +storj.io/uplink v1.13.1-0.20240522144333-931e862e9315 h1:e/slFmWr7UVY5XqtdnqlZZFtdIKOYi3riGzHWl9jL+w= +storj.io/uplink v1.13.1-0.20240522144333-931e862e9315/go.mod h1:MT8+V7qddgn1ra09piq3Idy4IUva2S90S7me7U8n6cE= storj.io/zipper v0.0.0-20220124122551-2ac2d53a46f6 h1:vJQmb+uAiYn8hVfkhMl6OqjnUyMWSCPnkzW8IsjF8vE= storj.io/zipper v0.0.0-20220124122551-2ac2d53a46f6/go.mod h1:MRnaO2kEXqZ+dd+InduHGg5RQy8gbrnPLaPp38CWDxg= diff --git a/pkg/server/config.go b/pkg/server/config.go index bb3dbd0b..0d7922f7 100644 --- a/pkg/server/config.go +++ b/pkg/server/config.go @@ -8,6 +8,7 @@ import ( "storj.io/common/memory" "storj.io/edge/pkg/authclient" + "storj.io/edge/pkg/uplinkutil" "storj.io/gateway/miniogw" ) @@ -86,6 +87,7 @@ type SatelliteConnectionPoolConfig struct { type ClientConfig struct { DialTimeout time.Duration `help:"timeout for dials" default:"10s"` MaximumBufferSize memory.Size `help:"maximum buffer size for DRPC streams" default:"304kB"` + Identity uplinkutil.IdentityConfig Upload uploadConfig } diff --git a/pkg/server/server.go b/pkg/server/server.go index d934c779..1f746eed 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -88,7 +88,10 @@ func New(config Config, log *zap.Logger, trustedIPs trustedip.List, corsAllowedO MaxLifetime: config.ConnectionPool.MaxLifetime, }) - uplinkConfig := configureUplinkConfig(config.Client) + uplinkConfig, err := configureUplinkConfig(config.Client) + if err != nil { + return nil, err + } layer, err := gw.NewMultiTenantLayer(miniogw.NewStorjGateway(config.S3Compatibility), satelliteConnectionPool, connectionPool, uplinkConfig, config.InsecureLogAll) if err != nil { @@ -194,10 +197,16 @@ func deduplicateDomains(domains string) (result []string) { } // configureUplinkConfig configures new uplink.Config using clientConfig. -func configureUplinkConfig(clientConfig ClientConfig) gw.UplinkConfig { +func configureUplinkConfig(clientConfig ClientConfig) (gw.UplinkConfig, error) { + clientCertPEM, clientKeyPEM, err := clientConfig.Identity.LoadPEMs() + if err != nil { + return gw.UplinkConfig{}, err + } ret := gw.UplinkConfig{ Base: uplink.Config{ DialTimeout: clientConfig.DialTimeout, + ChainPEM: clientCertPEM, + KeyPEM: clientKeyPEM, }, Uploads: gw.UploadConfig{ PieceHashAlgorithmBlake3: clientConfig.Upload.PieceHashAlgorithmBlake3, @@ -207,7 +216,7 @@ func configureUplinkConfig(clientConfig ClientConfig) gw.UplinkConfig { transport.SetMaximumBufferSize(&ret.Base, clientConfig.MaximumBufferSize.Int()) - return ret + return ret, nil } func (s *Peer) healthCheck(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/uplinkutil/config.go b/pkg/uplinkutil/config.go new file mode 100644 index 00000000..d7a31b91 --- /dev/null +++ b/pkg/uplinkutil/config.go @@ -0,0 +1,37 @@ +// Copyright (C) 2024 Storj Labs, Inc. +// See LICENSE for copying information. + +package uplinkutil + +import ( + "os" + + "github.com/zeebo/errs" +) + +// IdentityConfig is an intentional copy of identity.Config that has +// empty defaults. +type IdentityConfig struct { + CertPath string `help:"path to the certificate chain for this identity" default:"" user:"true" path:"true"` + KeyPath string `help:"path to the private key for this identity" default:"" user:"true" path:"true"` +} + +// LoadPEMs loads files and returns their byte strings if set. A possible +// return value of this function is nil, nil, nil. +func (c *IdentityConfig) LoadPEMs() (certPEM, keyPEM []byte, err error) { + if c.CertPath == "" && c.KeyPath == "" { + return nil, nil, nil + } + if c.CertPath == "" || c.KeyPath == "" { + return nil, nil, errs.New("only one of key path and cert path are set (%q, %q)", c.KeyPath, c.CertPath) + } + certPEM, err = os.ReadFile(c.CertPath) + if err != nil { + return nil, nil, errs.New("failed reading cert path %q: %+v", c.CertPath, err) + } + keyPEM, err = os.ReadFile(c.KeyPath) + if err != nil { + return nil, nil, errs.New("failed reading key path %q: %+v", c.KeyPath, err) + } + return certPEM, keyPEM, nil +} diff --git a/testsuite/go.mod b/testsuite/go.mod index 399a9d7b..8947e24f 100644 --- a/testsuite/go.mod +++ b/testsuite/go.mod @@ -16,7 +16,7 @@ require ( storj.io/edge v0.0.0-00010101000000-000000000000 storj.io/minio v0.0.0-20240517005305-6bf61e2db47a storj.io/storj v1.91.0-alpha.0.20240529222445-8d5ead827f2a - storj.io/uplink v1.13.0 + storj.io/uplink v1.13.1-0.20240522144333-931e862e9315 ) require ( diff --git a/testsuite/go.sum b/testsuite/go.sum index 626c06f0..b4c3133e 100644 --- a/testsuite/go.sum +++ b/testsuite/go.sum @@ -2721,7 +2721,7 @@ storj.io/picobuf v0.0.3/go.mod h1:4V4xelV1RSCck5GgmkL/Txw9l6IfX3XcBzegmL5Kudo= storj.io/storj v1.91.0-alpha.0.20240529222445-8d5ead827f2a h1:ZvqgwTjT2jDxvK8DPoiF5tVQxKi+2IQnlBDoMfBzuy4= storj.io/storj v1.91.0-alpha.0.20240529222445-8d5ead827f2a/go.mod h1:jl7/3zyG1hZ9nrY13nT/lCwgKo5R3CTBvJYfgZ/HPag= storj.io/uplink v1.7.1/go.mod h1:pKqsMpNMIAz//2TXzUGOR6tpu3iyabvXV4VWINj4jaY= -storj.io/uplink v1.13.0 h1:MAwzMaO4F86n2sMdNm7/m7LVyf8KD0FP+72h1H+HuRE= -storj.io/uplink v1.13.0/go.mod h1:MT8+V7qddgn1ra09piq3Idy4IUva2S90S7me7U8n6cE= +storj.io/uplink v1.13.1-0.20240522144333-931e862e9315 h1:e/slFmWr7UVY5XqtdnqlZZFtdIKOYi3riGzHWl9jL+w= +storj.io/uplink v1.13.1-0.20240522144333-931e862e9315/go.mod h1:MT8+V7qddgn1ra09piq3Idy4IUva2S90S7me7U8n6cE= storj.io/zipper v0.0.0-20220124122551-2ac2d53a46f6 h1:vJQmb+uAiYn8hVfkhMl6OqjnUyMWSCPnkzW8IsjF8vE= storj.io/zipper v0.0.0-20220124122551-2ac2d53a46f6/go.mod h1:MRnaO2kEXqZ+dd+InduHGg5RQy8gbrnPLaPp38CWDxg=