gcp/ic/main.go (126 lines of code) (raw):

// Copyright 2019 Google LLC // // 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. // This package provides a single-host reverse proxy that rewrites bearer // tokens in Authorization headers to be Google Cloud Platform access tokens. // For configuration information see app.yaml. package main import ( "context" "flag" "net/http" "os" "os/signal" "strings" "cloud.google.com/go/kms/apiv1" /* copybara-comment */ "cloud.google.com/go/logging" /* copybara-comment */ "github.com/gorilla/mux" /* copybara-comment */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/dsstore" /* copybara-comment: dsstore */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/grpcutil" /* copybara-comment: grpcutil */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/httputils" /* copybara-comment: httputils */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/hydraproxy" /* copybara-comment: hydraproxy */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/ic" /* copybara-comment: ic */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/kms/gcpcrypt" /* copybara-comment: gcpcrypt */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/kms/gcpsign" /* copybara-comment: gcpsign */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/osenv" /* copybara-comment: osenv */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/server" /* copybara-comment: server */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/serviceinfo" /* copybara-comment: serviceinfo */ "github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/storage" /* copybara-comment: storage */ glog "github.com/golang/glog" /* copybara-comment */ lgrpcpb "google.golang.org/genproto/googleapis/logging/v2" /* copybara-comment: logging_go_grpc */ ) var ( // srvName is the name of this service. srvName = osenv.VarWithDefault("SERVICE_NAME", "ic") // srvAddr determines the URL for "issuer" field of objects issued by this and // the address identity providers use to redirect back to IC. srvAddr = osenv.MustVar("SERVICE_DOMAIN") // accDomain is the postfix for accounts created by IC. acctDomain = osenv.MustVar("ACCOUNT_DOMAIN") // cfgPath is the path to the config file. cfgPath = osenv.MustVar("CONFIG_PATH") // project is default GCP project for hosting storage, // config options can override this. project = osenv.MustVar("PROJECT") // storageType determines we should be using in-mem storage or not. storageType = osenv.MustVar("STORAGE") port = osenv.VarWithDefault("IC_PORT", "8080") // skipInformationReleasePage is useful if IC and DAM provided by same org. // Use env var "SKIP_INFORMATION_RELEASE_PAGE" = true to set. skipInformationReleasePage = os.Getenv("SKIP_INFORMATION_RELEASE_PAGE") == "true" // consentDashboardURL is url to frontend consent dashboard, will replace // ${USER_ID} with userID. If it is not set point to howto doc on github // repo. consentDashboardURL = osenv.VarWithDefault("CONSENT_DASHBOARD_URL", "https://github.com/GoogleCloudPlatform/healthcare-federated-access-services/blob/0f366e73284377571bc314da7666e4b14233c3fa/howto.md#how-do-i-revoke-a-remembered-consent") useHydra = os.Getenv("USE_HYDRA") != "" // hydraAdminAddr is the address for the Hydra admin endpoint. hydraAdminAddr = "" // hydraPublicAddr is the address for the Hydra public endpoint. hydraPublicAddr = "" cfgVars = map[string]string{ "${YOUR_PROJECT_ID}": project, "${YOUR_ENVIRONMENT}": envPrefix(srvName), } // sldAddr is the address for Stackdriver Logging API. sdlAddr = osenv.VarWithDefault("SDL_ADDR", "logging.googleapis.com:443") ) func main() { flag.Parse() ctx := context.Background() serviceinfo.Project = project serviceinfo.Type = "ic" serviceinfo.Name = srvName sdlcc := grpcutil.NewGRPCClient(ctx, sdlAddr) defer sdlcc.Close() sdlc := lgrpcpb.NewLoggingServiceV2Client(sdlcc) var store storage.Store switch storageType { case "datastore": store = dsstore.NewStore(ctx, project, srvName, cfgPath) case "memory": store = storage.NewMemoryStorage(srvName, cfgPath) // Import and resolve template variables, if any. if err := ic.ImportConfig(store, srvName, cfgVars, true, true, true); err != nil { glog.Exitf("ic.ImportConfig(_, %q, _) failed: %v", srvName, err) } default: glog.Exitf("Unknown storage type: %q", storageType) } kmsClient, err := kms.NewKeyManagementClient(ctx) if err != nil { glog.Exitf("kms.NewKeyManagementClient(ctx) failed: %v", err) } gcpEncryption, err := gcpcrypt.New(ctx, project, "global", srvName+"_ring", srvName+"_key", kmsClient) if err != nil { glog.Exitf("gcpcrypt.New(ctx, %q, %q, %q, %q, kmsClient) failed: %v", project, "global", srvName+"_ring", srvName+"_key", err) } gcpSigner, err := gcpsign.New(ctx, project, "global", srvName+"_sign_ring", srvName+"_key", kmsClient) if err != nil { glog.Exitf("gcpsign.New(ctx, %q, %q, %q, %q, cliekmsClientnt) failed: %v", project, "global", srvName+"_sign_ring", srvName+"_key", err) } logger, err := logging.NewClient(ctx, project) if err != nil { glog.Exitf("logging.NewClient() failed: %v", err) } logger.OnError = func(err error) { glog.Warningf("StackdriverLogging.Client.OnError: %v", err) } var hyproxy *hydraproxy.Service if useHydra { hydraAdminAddr = osenv.MustVar("HYDRA_ADMIN_URL") hydraPublicAddr = osenv.MustVar("HYDRA_PUBLIC_URL") hydraPublicAddrInternal := osenv.MustVar("HYDRA_PUBLIC_URL_INTERNAL") hyproxy, err = hydraproxy.New(http.DefaultClient, hydraAdminAddr, hydraPublicAddrInternal, store) if err != nil { glog.Exitf("hydraproxy.New failed: %v", err) } } r := mux.NewRouter() s := ic.New(r, &ic.Options{ Domain: srvAddr, ServiceName: srvName, AccountDomain: acctDomain, Store: store, Encryption: gcpEncryption, Signer: gcpSigner, Logger: logger, SDLC: sdlc, AuditLogProject: project, SkipInformationReleasePage: skipInformationReleasePage, UseHydra: useHydra, HydraAdminURL: hydraAdminAddr, HydraPublicURL: hydraPublicAddr, HydraPublicProxy: hyproxy, ConsentDashboardURL: consentDashboardURL, }) r.HandleFunc("/liveness_check", httputils.LivenessCheckHandler) srv := server.New("ic", port, s.Handler) srv.ServeUnblock() c := make(chan os.Signal, 1) // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught. signal.Notify(c, os.Interrupt) // Block until we receive our signal. <-c srv.Shutdown() } func envPrefix(name string) string { if strings.Contains(name, "-") { return "-" + strings.SplitN(name, "-", 2)[1] } return "" }