From cc58a3da7d647de8520e33dc4356672d2ed1a366 Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Tue, 16 Nov 2021 14:46:24 -0800 Subject: Import of source code --- cmd/web/server.go | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 cmd/web/server.go (limited to 'cmd') diff --git a/cmd/web/server.go b/cmd/web/server.go new file mode 100644 index 0000000..e76b6b2 --- /dev/null +++ b/cmd/web/server.go @@ -0,0 +1,155 @@ +package web + +import ( + "context" + "io/fs" + "log" + "os" + "time" + + "code.crute.us/mcrute/cloud-identity-broker/app" + "code.crute.us/mcrute/cloud-identity-broker/app/controllers" + "code.crute.us/mcrute/cloud-identity-broker/app/middleware" + "code.crute.us/mcrute/cloud-identity-broker/app/models" + "code.crute.us/mcrute/cloud-identity-broker/auth" + "code.crute.us/mcrute/cloud-identity-broker/auth/github" + + "code.crute.us/mcrute/golib/crypto/tls" + "code.crute.us/mcrute/golib/db/mongodb" + glecho "code.crute.us/mcrute/golib/echo" + glmw "code.crute.us/mcrute/golib/echo/middleware" + "code.crute.us/mcrute/golib/service" + "github.com/labstack/echo/v4" + echomw "github.com/labstack/echo/v4/middleware" + "github.com/spf13/cobra" + "golang.org/x/time/rate" +) + +func Register(root *cobra.Command, embeddedTemplates fs.FS) { + webCmd := &cobra.Command{ + Use: "web [options]", + Short: "Run web server", + Run: func(c *cobra.Command, args []string) { + webMain(app.NewConfigFromCmd(c), embeddedTemplates) + }, + } + + webCmd.Flags().StringSlice("bind", []string{":8169"}, "Addresses and ports to bind http server") + webCmd.Flags().StringSlice("bind-tls", []string{":8170"}, "Addresses and ports to bind https server") + webCmd.Flags().String("log-file", "", "Log file for combined host logs") + webCmd.Flags().String("tls-cache-dir", "ssl/", "Cache directory for TLS certificates") + webCmd.Flags().StringSlice("trusted-ip-ranges", []string{"172.19.0.0/22", "2602:803:4072::/48"}, "Comma separated list of IP ranges for trusted XFF proxies") + webCmd.Flags().StringSlice("management-ip-ranges", []string{"127.0.0.1/32", "::1/128", "172.19.0.0/22", "2602:803:4072::/48"}, "IP ranges for management systems") + webCmd.Flags().StringSlice("hostname", []string{"dev.aws-access.crute.us"}, "Hostname this server serves (can be specified multiple times)") + webCmd.Flags().Duration("rate-limit", 30*time.Second, "Number seconds between requests for credential resources") + webCmd.Flags().Duration("auth-cookie-duration", 24*time.Hour, "Expiration duration of the auth cookies") + webCmd.Flags().Int("rate-limit-burst", 30, "Number of burst requests allowed to credential endpoints") + webCmd.Flags().String("issuer-endpoint", "https://aws-access.crute.us", "Oauth issuer endpoint") + webCmd.Flags().String("jwt-audience", "aws-access", "Audience for issued JWTs") + + webCmd.Flags().String("github-oauth-vault-path", "", "Vault material name for GitHub auth credentials") + webCmd.MarkFlagRequired("github-oauth-vault-path") + + root.AddCommand(webCmd) +} + +func webMain(cfg app.Config, embeddedTemplates fs.FS) { + ctx := context.Background() + + s, err := glecho.NewDefaultEchoWithConfig(glecho.EchoConfig{ + Debug: cfg.Debug, + Hostnames: cfg.Hostnames, + BindAddresses: cfg.Bind, + BindTLSAddresses: cfg.BindTLS, + TLSCacheDir: cfg.TLSCacheDir, + TrustedProxyIPRanges: cfg.TrustedIPRanges, + ManagementIPRanges: cfg.ManagementIPRanges, + DiskTemplates: os.DirFS(cfg.TemplatePath), + EmbeddedTemplates: embeddedTemplates, + TemplateGlob: &cfg.TemplateGlob, + CombinedHostLogFile: cfg.LogFile, + ContentSecurityPolicy: &glmw.ContentSecurityPolicyConfig{ + DefaultSrc: []glmw.CSPDirective{ + glmw.CSPSelf, + glmw.CSPUnsafeInline, + }, + StyleSrc: []glmw.CSPDirective{ + glmw.CSPSelf, + glmw.CSPData, + glmw.CSPUnsafeInline, + }, + }, + }) + if err != nil { + log.Fatalf("Error building echo: %w", err) + } + if err = s.Init(); err != nil { + log.Fatalf("Error initializing echo: %w", err) + } + + mongo, err := mongodb.Connect(ctx, cfg.MongoDbUri, cfg.MongodbVaultPath) + if err != nil { + log.Fatalf("Error connecting to mongodb: %w", err) + } + + rateLimit := echomw.RateLimiter( + echomw.NewRateLimiterMemoryStoreWithConfig( + echomw.RateLimiterMemoryStoreConfig{ + Rate: rate.Every(cfg.RateLimit), + Burst: cfg.RateLimitBurst, + ExpiresIn: time.Hour, + }, + ), + ) + + as := &models.MongoDbAccountStore{Db: mongo} + us := &models.MongoDbUserStore{Db: mongo} + + aws := &controllers.AWSAPI{Store: as} + + am := &middleware.AuthenticationMiddleware{ + Store: us, + CookieDuration: cfg.AuthCookieDuration, + GitHub: &github.GitHubAuthenticator{ + ClientId: cfg.GitHubOauthCreds.ClientId, + ClientSecret: cfg.GitHubOauthCreds.ClientSecret, + }, + JWTManager: &auth.JWTManager{ + Store: us, + Audience: cfg.JWTAudience, + TokenExpires: cfg.AuthCookieDuration, + }, + } + am.RegisterUrls(s) + + api := s.Group("/api/account") + api.Use(glmw.VaryCookie()) + api.Use(glmw.CacheNeverMiddleware) + api.Use(am.Middleware) + { + api.GET("", controllers.NewAPIAccountListHandler(as)) + api.GET( + "/:account/credentials", + controllers.NewAPIRegionListHandler(aws), + ) + api.GET( + "/:account/console", + controllers.NewAPIConsoleRedirectHandler(aws, cfg.IssuerEndpoint), + rateLimit, + ) + api.GET( + "/:account/credentials/:region", + controllers.NewAPICredentialsHandler(aws), + rateLimit, + ) + } + s.GET("/favicon.ico", echo.NotFoundHandler) + s.GET("/logout", controllers.LogoutHandler) + s.GET("/", controllers.IndexHandler, am.Middleware) + + runner := service.NewAppRunner(ctx, s.Logger) + runner.AddJob(s.RunCertificateManager) // Cert manager has to start before server + runner.AddJob(tls.OcspErrorLogger(s.Logger, s.OcspErrors())) + runner.AddJobs(s.MakeServerJobs()) + runner.RunForever(!cfg.DisableBackgroundJobs) +} -- cgit v1.2.3