From 5ab38e3dabe44adc0e5cde1e32450ef16b94ff9f Mon Sep 17 00:00:00 2001 From: jonaustin09 Date: Tue, 12 Sep 2023 14:43:20 -0400 Subject: [PATCH] feat: Closes #232, Added an option to run admin server in a different network, by specifying admin server address/ip --- cmd/versitygw/main.go | 53 +++++++++++++++++++++++++++++-- s3api/admin-router.go | 43 ++++++++++++++++++++++++++ s3api/admin-server.go | 72 +++++++++++++++++++++++++++++++++++++++++++ s3api/router.go | 29 +++++++++-------- s3api/server.go | 5 +++ 5 files changed, 187 insertions(+), 15 deletions(-) create mode 100644 s3api/admin-router.go create mode 100644 s3api/admin-server.go diff --git a/cmd/versitygw/main.go b/cmd/versitygw/main.go index a2af5b9..1590638 100644 --- a/cmd/versitygw/main.go +++ b/cmd/versitygw/main.go @@ -33,10 +33,11 @@ import ( ) var ( - port string + port, admPort string rootUserAccess string rootUserSecret string region string + admCertFile, admKeyFile string certFile, keyFile string kafkaURL, kafkaTopic, kafkaKey string natsURL, natsTopic string @@ -143,6 +144,22 @@ func initFlags() []cli.Flag { Usage: "TLS key file", Destination: &keyFile, }, + &cli.StringFlag{ + Name: "admin-port", + Usage: "gateway admin server listen address : or :", + Destination: &admPort, + Aliases: []string{"ap"}, + }, + &cli.StringFlag{ + Name: "admin-cert", + Usage: "TLS cert file for admin server", + Destination: &admCertFile, + }, + &cli.StringFlag{ + Name: "admin-cert-key", + Usage: "TLS key file for admin server", + Destination: &admKeyFile, + }, &cli.BoolFlag{ Name: "debug", Usage: "enable debug output", @@ -223,10 +240,35 @@ func runGateway(ctx *cli.Context, be backend.Backend, s auth.Storer) error { } opts = append(opts, s3api.WithTLS(cert)) } - if debug { opts = append(opts, s3api.WithDebug()) } + if admPort == "" { + opts = append(opts, s3api.WithAdminServer()) + } + + admApp := fiber.New(fiber.Config{ + AppName: "versitygw", + ServerHeader: "VERSITYGW", + BodyLimit: 5 * 1024 * 1024 * 1024, + }) + + var admOpts []s3api.AdminOpt + + if admCertFile != "" || admKeyFile != "" { + if admCertFile == "" { + return fmt.Errorf("TLS key specified without cert file") + } + if admKeyFile == "" { + return fmt.Errorf("TLS cert specified without key file") + } + + cert, err := tls.LoadX509KeyPair(admCertFile, admKeyFile) + if err != nil { + return fmt.Errorf("tls: load certs: %v", err) + } + admOpts = append(admOpts, s3api.WithAdminSrvTLS(cert)) + } err := s.InitIAM() if err != nil { @@ -265,8 +307,13 @@ func runGateway(ctx *cli.Context, be backend.Backend, s auth.Storer) error { return fmt.Errorf("init gateway: %v", err) } - c := make(chan error, 1) + admSrv := s3api.NewAdminServer(admApp, be, middlewares.RootUserConfig{Access: rootUserAccess, Secret: rootUserSecret}, admPort, region, iam, admOpts...) + + c := make(chan error, 2) go func() { c <- srv.Serve() }() + if admPort != "" { + go func() { c <- admSrv.Serve() }() + } // for/select blocks until shutdown Loop: diff --git a/s3api/admin-router.go b/s3api/admin-router.go new file mode 100644 index 0000000..8aef22d --- /dev/null +++ b/s3api/admin-router.go @@ -0,0 +1,43 @@ +// Copyright 2023 Versity Software +// This file is licensed under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package s3api + +import ( + "github.com/gofiber/fiber/v2" + "github.com/versity/versitygw/auth" + "github.com/versity/versitygw/backend" + "github.com/versity/versitygw/s3api/controllers" +) + +type S3AdminRouter struct{} + +func (ar *S3AdminRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMService) { + controller := controllers.NewAdminController(iam, be) + + // CreateUser admin api + app.Patch("/create-user", controller.CreateUser) + + // DeleteUsers admin api + app.Patch("/delete-user", controller.DeleteUser) + + // ListUsers admin api + app.Patch("/list-users", controller.ListUsers) + + // ChangeBucketOwner admin api + app.Patch("/change-bucket-owner", controller.ChangeBucketOwner) + + // ListBucketsAndOwners admin api + app.Patch("/list-buckets", controller.ListBuckets) +} diff --git a/s3api/admin-server.go b/s3api/admin-server.go new file mode 100644 index 0000000..b00f82a --- /dev/null +++ b/s3api/admin-server.go @@ -0,0 +1,72 @@ +// Copyright 2023 Versity Software +// This file is licensed under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package s3api + +import ( + "crypto/tls" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/logger" + "github.com/versity/versitygw/auth" + "github.com/versity/versitygw/backend" + "github.com/versity/versitygw/s3api/middlewares" +) + +type S3AdminServer struct { + app *fiber.App + backend backend.Backend + router *S3AdminRouter + port string + cert *tls.Certificate +} + +func NewAdminServer(app *fiber.App, be backend.Backend, root middlewares.RootUserConfig, port, region string, iam auth.IAMService, opts ...AdminOpt) *S3AdminServer { + server := &S3AdminServer{ + app: app, + backend: be, + router: new(S3AdminRouter), + port: port, + } + + for _, opt := range opts { + opt(server) + } + + // Logging middlewares + app.Use(logger.New()) + app.Use(middlewares.DecodeURL(nil)) + + // Authentication middlewares + app.Use(middlewares.VerifyV4Signature(root, iam, nil, region, false)) + app.Use(middlewares.VerifyMD5Body(nil)) + app.Use(middlewares.AclParser(be, nil)) + + server.router.Init(app, be, iam) + + return server +} + +type AdminOpt func(s *S3AdminServer) + +func WithAdminSrvTLS(cert tls.Certificate) AdminOpt { + return func(s *S3AdminServer) { s.cert = &cert } +} + +func (sa *S3AdminServer) Serve() (err error) { + if sa.cert != nil { + return sa.app.ListenTLSWithCertificate(sa.port, *sa.cert) + } + return sa.app.Listen(sa.port) +} diff --git a/s3api/router.go b/s3api/router.go index f9eaa42..d0886b0 100644 --- a/s3api/router.go +++ b/s3api/router.go @@ -23,26 +23,31 @@ import ( "github.com/versity/versitygw/s3log" ) -type S3ApiRouter struct{} +type S3ApiRouter struct { + WithAdmSrv bool +} func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMService, logger s3log.AuditLogger, evs s3event.S3EventSender) { s3ApiController := controllers.New(be, iam, logger, evs) - adminController := controllers.NewAdminController(iam, be) - // CreateUser admin api - app.Patch("/create-user", adminController.CreateUser) + if sa.WithAdmSrv { + adminController := controllers.NewAdminController(iam, be) - // DeleteUsers admin api - app.Patch("/delete-user", adminController.DeleteUser) + // CreateUser admin api + app.Patch("/create-user", adminController.CreateUser) - // ListUsers admin api - app.Patch("/list-users", adminController.ListUsers) + // DeleteUsers admin api + app.Patch("/delete-user", adminController.DeleteUser) - // ChangeBucketOwner admin api - app.Patch("/change-bucket-owner", adminController.ChangeBucketOwner) + // ListUsers admin api + app.Patch("/list-users", adminController.ListUsers) - // ListBucketsAndOwners admin api - app.Patch("/list-buckets", adminController.ListBuckets) + // ChangeBucketOwner admin api + app.Patch("/change-bucket-owner", adminController.ChangeBucketOwner) + + // ListBucketsAndOwners admin api + app.Patch("/list-buckets", adminController.ListBuckets) + } // ListBuckets action app.Get("/", s3ApiController.ListBuckets) diff --git a/s3api/server.go b/s3api/server.go index 57bb46f..0cbee9b 100644 --- a/s3api/server.go +++ b/s3api/server.go @@ -70,6 +70,11 @@ func WithTLS(cert tls.Certificate) Option { return func(s *S3ApiServer) { s.cert = &cert } } +// WithAdminServer runs admin endpoints with the gateway in the same network +func WithAdminServer() Option { + return func(s *S3ApiServer) { s.router.WithAdmSrv = true } +} + // WithDebug sets debug output func WithDebug() Option { return func(s *S3ApiServer) { s.debug = true }