Просмотр исходного кода

ECR CAPI support (#2791)

* linting changes

* added callout to capi for capi projects
Stefan McShane 3 лет назад
Родитель
Сommit
725095e03e

+ 2 - 0
Tiltfile

@@ -62,6 +62,8 @@ local_resource(
     resource_deps=["postgresql"],
     labels=["porter"]
 )
+# local_resource('public-url', serve_cmd='lt --subdomain "$(whoami)" --port 8080', resource_deps=["porter-dashboard"], labels=["porter"])
+# local_resource('public-url', serve_cmd='ngrok http 8081 --log=stdout', resource_deps=["porter-dashboard"], labels=["porter"])
 
 # Migrations
 local_resource(

+ 1 - 1
api/server/handlers/api_contract/update.go

@@ -47,7 +47,7 @@ func (c *APIContractUpdateHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
 		return
 	}
 
-	if !project.CapiProvisionerEnabled && c.Config().DisableCAPIProvisioner {
+	if !project.CapiProvisionerEnabled && !c.Config().EnableCAPIProvisioner {
 		// return dummy data if capi provisioner disabled in project settings, and as env var
 		// TODO: remove this stub when we can spin up all services locally, easily
 		clusterID := apiContract.Cluster.ClusterId

+ 1 - 1
api/server/handlers/cluster/delete.go

@@ -35,7 +35,7 @@ func (c *ClusterDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
 
 	if cluster.ProvisionedBy == "CAPI" {
-		if !c.Config().DisableCAPIProvisioner {
+		if c.Config().EnableCAPIProvisioner {
 			revisions, err := c.Config().Repo.APIContractRevisioner().List(ctx, cluster.ProjectID, cluster.ID)
 			if err != nil {
 				e := fmt.Errorf("error listing revisions for cluster %d: %w", cluster.ID, err)

+ 1 - 1
api/server/handlers/project_integration/create_aws.go

@@ -51,7 +51,7 @@ func (p *CreateAWSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		AWSIntegration: aws.ToAWSIntegrationType(),
 	}
 
-	if project.CapiProvisionerEnabled && !p.Config().DisableCAPIProvisioner {
+	if project.CapiProvisionerEnabled && p.Config().EnableCAPIProvisioner {
 		credReq := porterv1.CreateAssumeRoleChainRequest{
 			ProjectId:       int64(project.ID),
 			SourceArn:       "arn:aws:iam::108458755588:role/CAPIManagement", // hard coded as this is the final hop for a CAPI cluster

+ 3 - 2
api/server/handlers/registry/create_repository.go

@@ -28,7 +28,8 @@ func NewRegistryCreateRepositoryHandler(
 }
 
 func (p *RegistryCreateRepositoryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	reg, _ := r.Context().Value(types.RegistryScope).(*models.Registry)
+	ctx := r.Context()
+	reg, _ := ctx.Value(types.RegistryScope).(*models.Registry)
 
 	request := &types.CreateRegistryRepositoryRequest{}
 
@@ -45,7 +46,7 @@ func (p *RegistryCreateRepositoryHandler) ServeHTTP(w http.ResponseWriter, r *ht
 	nameSpl := strings.Split(request.ImageRepoURI, "/")
 	repoName := strings.ToLower(strings.ReplaceAll(nameSpl[len(nameSpl)-1], "_", "-"))
 
-	err := regAPI.CreateRepository(p.Repo(), repoName)
+	err := regAPI.CreateRepository(ctx, p.Config(), repoName)
 	if err != nil {
 		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 32 - 1
api/server/handlers/registry/get_token.go

@@ -2,11 +2,14 @@ package registry
 
 import (
 	"encoding/base64"
+	"fmt"
 	"net/http"
 	"strings"
 	"time"
 
 	"github.com/aws/aws-sdk-go/service/ecr"
+	"github.com/bufbuild/connect-go"
+	porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
@@ -34,7 +37,8 @@ func NewRegistryGetECRTokenHandler(
 }
 
 func (c *RegistryGetECRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+	ctx := r.Context()
+	proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
 
 	request := &types.GetRegistryECRTokenRequest{}
 
@@ -42,6 +46,33 @@ func (c *RegistryGetECRTokenHandler) ServeHTTP(w http.ResponseWriter, r *http.Re
 		return
 	}
 
+	if proj.CapiProvisionerEnabled {
+		ecrRequest := porterv1.ECRTokenForRegistryRequest{
+			ProjectId:    int64(proj.ID),
+			Region:       request.Region,
+			AwsAccountId: request.AccountID,
+		}
+		ecrResponse, err := c.Config().ClusterControlPlaneClient.ECRTokenForRegistry(ctx, connect.NewRequest(&ecrRequest))
+		if err != nil {
+			e := fmt.Errorf("error getting ecr token for capi cluster: %v", err)
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
+			return
+		}
+		if ecrResponse.Msg == nil {
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("nil message received for ecr token")))
+			return
+		}
+		expiry := ecrResponse.Msg.Expiry.AsTime()
+
+		resp := &types.GetRegistryTokenResponse{
+			Token:     ecrResponse.Msg.Token,
+			ExpiresAt: &expiry,
+		}
+
+		c.WriteResult(w, r, resp)
+		return
+	}
+
 	// list registries and find one that matches the region
 	regs, err := c.Repo().Registry().ListRegistriesByProjectID(proj.ID)
 	if err != nil {

+ 3 - 2
api/server/handlers/registry/list_repositories.go

@@ -26,13 +26,14 @@ func NewRegistryListRepositoriesHandler(
 }
 
 func (c *RegistryListRepositoriesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	reg, _ := r.Context().Value(types.RegistryScope).(*models.Registry)
+	ctx := r.Context()
+	reg, _ := ctx.Value(types.RegistryScope).(*models.Registry)
 
 	// cast to a registry from registry package
 	_reg := registry.Registry(*reg)
 	regAPI := &_reg
 
-	repos, err := regAPI.ListRepositories(c.Repo(), c.Config().DOConf)
+	repos, err := regAPI.ListRepositories(ctx, c.Repo(), c.Config())
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return

+ 8 - 4
api/server/handlers/release/create.go

@@ -1,6 +1,7 @@
 package release
 
 import (
+	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -48,9 +49,10 @@ func NewCreateReleaseHandler(
 }
 
 func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	user, _ := r.Context().Value(types.UserScope).(*models.User)
-	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
-	namespace := r.Context().Value(types.NamespaceScope).(string)
+	ctx := r.Context()
+	user, _ := ctx.Value(types.UserScope).(*models.User)
+	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
+	namespace := ctx.Value(types.NamespaceScope).(string)
 	operationID := oauth.CreateRandomState()
 
 	c.Config().AnalyticsClient.Track(analytics.ApplicationLaunchStartTrack(
@@ -190,6 +192,7 @@ func (c *CreateReleaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 
 	if request.GitActionConfig != nil {
 		_, _, err := createGitAction(
+			ctx,
 			c.Config(),
 			user.ID,
 			cluster.ProjectID,
@@ -286,6 +289,7 @@ func CreateAddonReleaseFromHelmRelease(
 }
 
 func createGitAction(
+	ctx context.Context,
 	config *config.Config,
 	userID, projectID, clusterID uint,
 	request *types.CreateGitActionConfigRequest,
@@ -307,7 +311,7 @@ func createGitAction(
 		nameSpl := strings.Split(request.ImageRepoURI, "/")
 		repoName := nameSpl[len(nameSpl)-1]
 
-		err = regAPI.CreateRepository(config.Repo, repoName)
+		err = regAPI.CreateRepository(ctx, config, repoName)
 
 		if err != nil {
 			return nil, nil, err

+ 5 - 3
api/server/handlers/release/get_gha_template.go

@@ -26,9 +26,10 @@ func NewGetGHATemplateHandler(
 }
 
 func (c *GetGHATemplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	user, _ := r.Context().Value(types.UserScope).(*models.User)
-	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
-	namespace := r.Context().Value(types.NamespaceScope).(string)
+	ctx := r.Context()
+	user, _ := ctx.Value(types.UserScope).(*models.User)
+	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
+	namespace := ctx.Value(types.NamespaceScope).(string)
 
 	request := &types.GetGHATemplateRequest{}
 
@@ -37,6 +38,7 @@ func (c *GetGHATemplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
 	}
 
 	_, workflowYAML, err := createGitAction(
+		ctx, 
 		c.Config(),
 		user.ID,
 		cluster.ProjectID,

+ 2 - 2
api/server/shared/config/config.go

@@ -105,8 +105,8 @@ type Config struct {
 	// NATS contains the required config for connecting to a NATS cluster for streaming
 	NATS nats.NATS
 
-	// DisableCAPIProvisioner disables checks for ClusterControlPlaneClient and NATS, if set to true
-	DisableCAPIProvisioner bool
+	// EnableCAPIProvisioner enables CAPI Provisioner, which requires config for ClusterControlPlaneClient and NATS, if set to true
+	EnableCAPIProvisioner bool
 }
 
 type ConfigLoader interface {

+ 3 - 4
api/server/shared/config/env/envconfs.go

@@ -124,11 +124,10 @@ type ServerConf struct {
 	// /api/projects/{project_id}/clusters/{cluster_id}/kubeconfig will be disabled.
 	DisableTemporaryKubeconfig bool `env:"DISABLE_TEMPORARY_KUBECONFIG,default=false"`
 
-	// NATSUrl is the URL of the NATS cluster
+	// EnableCAPIProvisioner disables checks for ClusterControlPlaneClient and NATS, if set to true
+	EnableCAPIProvisioner bool `env:"ENABLE_CAPI_PROVISIONER"`
+	// NATSUrl is the URL of the NATS cluster. This is required if ENABLE_CAPI_PROVISIONER is true
 	NATSUrl string `env:"NATS_URL"`
-
-	// DisableCAPIProvisioner disables checks for ClusterControlPlaneClient and NATS, if set to true
-	DisableCAPIProvisioner bool `env:"DISABLE_CAPI_PROVISIONER"`
 }
 
 // DBConf is the database configuration: if generated from environment variables,

+ 29 - 35
api/server/shared/config/loader/loader.go

@@ -4,9 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"io/ioutil"
-	// 	"net"
 	"net/http"
-	// 	"net/url"
 	"strconv"
 
 	gorillaws "github.com/gorilla/websocket"
@@ -206,28 +204,33 @@ func (e *EnvConfigLoader) LoadConfig() (res *config.Config, err error) {
 			CheckOrigin: func(r *http.Request) bool {
 				origin := r.Header.Get("Origin")
 
-				// check if the server url is localhost, and allow all localhost origins
-				//serverParsed, err := url.Parse(sc.ServerURL)
-				//if err != nil {
-				//return false
-				//}
-				//host, _, err := net.SplitHostPort(serverParsed.Host)
-				//if err != nil {
-				//return false
-				//}
-				//if host == "localhost" {
-				//parsedOrigin, err := url.Parse(origin)
-				//if err != nil {
-				//return false
-				//}
-				//originHost, _, err := net.SplitHostPort(parsedOrigin.Host)
-				//if err != nil {
-				//return false
-				//}
-				//if originHost == "localhost" {
-				//return true
-				//}
-				//}
+				// // check if the server url is localhost, and allow all localhost origins
+				// serverParsed, err := url.Parse(sc.ServerURL)
+				// if err != nil {
+				// 	return false
+				// }
+				// host, _, err := net.SplitHostPort(serverParsed.Host)
+				// if err != nil {
+				// 	return false
+				// }
+				// if host == "localhost" {
+				// 	parsedOrigin, err := url.Parse(origin)
+				// 	if err != nil {
+				// 		return false
+				// 	}
+				// 	originHost, _, err := net.SplitHostPort(parsedOrigin.Host)
+				// 	if err != nil {
+				// 		if !strings.Contains(err.Error(), "missing port in address") {
+				// 			return false
+				// 		}
+				// 		if strings.Contains(parsedOrigin.Host, "ngrok.io") {
+				// 			return true
+				// 		}
+				// 	}
+				// 	if originHost == "localhost" {
+				// 		return true
+				// 	}
+				// }
 				return origin == sc.ServerURL
 			},
 		},
@@ -256,22 +259,13 @@ func (e *EnvConfigLoader) LoadConfig() (res *config.Config, err error) {
 		res.PowerDNSClient = powerdns.NewClient(sc.PowerDNSAPIServerURL, sc.PowerDNSAPIKey, sc.AppRootDomain)
 	}
 
-	res.DisableCAPIProvisioner = sc.DisableCAPIProvisioner
-	if !sc.DisableCAPIProvisioner {
+	res.EnableCAPIProvisioner = sc.EnableCAPIProvisioner
+	if sc.EnableCAPIProvisioner {
 		if sc.ClusterControlPlaneAddress == "" {
 			return res, errors.New("must provide CLUSTER_CONTROL_PLANE_ADDRESS")
 		}
 		client := porterv1connect.NewClusterControlPlaneServiceClient(http.DefaultClient, sc.ClusterControlPlaneAddress)
 		res.ClusterControlPlaneClient = client
-
-		// if sc.NATSUrl == "" {
-		// 	return res, errors.New("must provide NATS_URL")
-		// }
-		// pnats, err := nats.NewConnection(ctx, nats.Config{URL: sc.NATSUrl})
-		// if err != nil {
-		// 	return res, fmt.Errorf("error setting up connection to NATS cluster: %w", err)
-		// }
-		// res.NATS = pnats
 	}
 
 	return res, nil

+ 1 - 1
go.mod

@@ -74,7 +74,7 @@ require (
 	github.com/glebarez/sqlite v1.6.0
 	github.com/nats-io/nats.go v1.24.0
 	github.com/open-policy-agent/opa v0.44.0
-	github.com/porter-dev/api-contracts v0.0.52
+	github.com/porter-dev/api-contracts v0.0.56
 	github.com/santhosh-tekuri/jsonschema/v5 v5.0.1
 	github.com/stefanmcshane/helm v0.0.0-20221213002717-88a4a2c6e77d
 	github.com/xanzy/go-gitlab v0.68.0

+ 0 - 4
go.sum

@@ -1466,10 +1466,6 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
-github.com/porter-dev/api-contracts v0.0.47 h1:27oAGW8i+SXQFF3LZG0FrGz7KUolNenbjRPPn0/V+og=
-github.com/porter-dev/api-contracts v0.0.47/go.mod h1:qr2L58mJLr5DUGV5OPw3REiSrQvJq6TgkKyEWP95dyU=
-github.com/porter-dev/api-contracts v0.0.52 h1:T+eCdX6r3cXsfNQ+Us9ur7+q72vMkMS3URaIUUrZtbQ=
-github.com/porter-dev/api-contracts v0.0.52/go.mod h1:qr2L58mJLr5DUGV5OPw3REiSrQvJq6TgkKyEWP95dyU=
 github.com/porter-dev/switchboard v0.0.0-20221019155755-67ff2bf04935 h1:hfb3nt3AJXIBbevu6ARTg9SdOkMP6WLbKBiG5hT5rcc=
 github.com/porter-dev/switchboard v0.0.0-20221019155755-67ff2bf04935/go.mod h1:xSPzqSFMQ6OSbp42fhCi4AbGbQbsm6nRvOkrblFeXU4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=

+ 2 - 0
go.work.sum

@@ -14,6 +14,8 @@ github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f h1:2+myh5ml7lgEU/5
 github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=
 github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4=
 github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
+github.com/porter-dev/api-contracts v0.0.56 h1:4PpnLfiXvvl70pgmTw+Nr1//sZyNo/RSVA61GYIU+u8=
+github.com/porter-dev/api-contracts v0.0.56/go.mod h1:qr2L58mJLr5DUGV5OPw3REiSrQvJq6TgkKyEWP95dyU=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
 github.com/tchap/go-patricia v2.2.6+incompatible h1:JvoDL7JSoIP2HDE8AbDH3zC8QBPxmzYe32HHy5yQ+Ck=
 golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=

+ 81 - 24
internal/registry/registry.go

@@ -15,6 +15,9 @@ import (
 	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
 	"github.com/aws/aws-sdk-go/aws/awserr"
 	"github.com/aws/aws-sdk-go/service/ecr"
+	"github.com/bufbuild/connect-go"
+	porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
+	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/oauth"
 	"github.com/porter-dev/porter/internal/repository"
@@ -64,12 +67,20 @@ func GetECRRegistryURL(awsIntRepo repository.AWSIntegrationRepository, projectID
 
 // ListRepositories lists the repositories for a registry
 func (r *Registry) ListRepositories(
+	ctx context.Context,
 	repo repository.Repository,
-	doAuth *oauth2.Config, // only required if using DOCR
+	conf *config.Config,
 ) ([]*ptypes.RegistryRepository, error) {
 	// switch on the auth mechanism to get a token
 	if r.AWSIntegrationID != 0 {
-		return r.listECRRepositories(repo)
+		aws, err := repo.AWSIntegration().ReadAWSIntegration(
+			r.ProjectID,
+			r.AWSIntegrationID,
+		)
+		if err != nil {
+			return nil, err
+		}
+		return r.listECRRepositories(aws)
 	}
 
 	if r.GCPIntegrationID != 0 {
@@ -81,7 +92,7 @@ func (r *Registry) ListRepositories(
 	}
 
 	if r.DOIntegrationID != 0 {
-		return r.listDOCRRepositories(repo, doAuth)
+		return r.listDOCRRepositories(repo, conf.DOConf)
 	}
 
 	if r.AzureIntegrationID != 0 {
@@ -92,6 +103,33 @@ func (r *Registry) ListRepositories(
 		return r.listPrivateRegistryRepositories(repo)
 	}
 
+	project, err := conf.Repo.Project().ReadProject(r.ProjectID)
+	if err != nil {
+		return nil, fmt.Errorf("error getting project for repository: %w", err)
+	}
+
+	if project.CapiProvisionerEnabled {
+		uri := strings.TrimPrefix(r.URL, "https://")
+		splits := strings.Split(uri, ".")
+		accountID := splits[0]
+		region := splits[3]
+		req := connect.NewRequest(&porterv1.AssumeRoleCredentialsRequest{
+			ProjectId:    int64(r.ProjectID),
+			AwsAccountId: accountID,
+		})
+		creds, err := conf.ClusterControlPlaneClient.AssumeRoleCredentials(ctx, req)
+		if err != nil {
+			return nil, fmt.Errorf("error getting capi credentials for repository: %w", err)
+		}
+		aws := &ints.AWSIntegration{
+			AWSAccessKeyID:     []byte(creds.Msg.AwsAccessId),
+			AWSSecretAccessKey: []byte(creds.Msg.AwsSecretKey),
+			AWSSessionToken:    []byte(creds.Msg.AwsSessionToken),
+			AWSRegion:          region,
+		}
+		return r.listECRRepositories(aws)
+	}
+
 	return nil, fmt.Errorf("error listing repositories")
 }
 
@@ -364,15 +402,7 @@ func (r *Registry) listGARRepositories(
 	return res, nil
 }
 
-func (r *Registry) listECRRepositories(repo repository.Repository) ([]*ptypes.RegistryRepository, error) {
-	aws, err := repo.AWSIntegration().ReadAWSIntegration(
-		r.ProjectID,
-		r.AWSIntegrationID,
-	)
-	if err != nil {
-		return nil, err
-	}
-
+func (r *Registry) listECRRepositories(aws *ints.AWSIntegration) ([]*ptypes.RegistryRepository, error) {
 	sess, err := aws.GetSession()
 	if err != nil {
 		return nil, err
@@ -720,14 +750,49 @@ func (r *Registry) setTokenCacheFunc(
 // CreateRepository creates a repository for a registry, if needed
 // (currently only required for ECR)
 func (r *Registry) CreateRepository(
-	repo repository.Repository,
+	ctx context.Context,
+	conf *config.Config,
 	name string,
 ) error {
 	// if aws, create repository
 	if r.AWSIntegrationID != 0 {
-		return r.createECRRepository(repo, name)
+		aws, err := conf.Repo.AWSIntegration().ReadAWSIntegration(
+			r.ProjectID,
+			r.AWSIntegrationID,
+		)
+		if err != nil {
+			return err
+		}
+		return r.createECRRepository(aws, name)
 	} else if r.GCPIntegrationID != 0 && strings.Contains(r.URL, "pkg.dev") {
-		return r.createGARRepository(repo, name)
+		return r.createGARRepository(conf.Repo, name)
+	}
+
+	project, err := conf.Repo.Project().ReadProject(r.ProjectID)
+	if err != nil {
+		return fmt.Errorf("error getting project for repository: %w", err)
+	}
+
+	if project.CapiProvisionerEnabled {
+		uri := strings.TrimPrefix(r.URL, "https://")
+		splits := strings.Split(uri, ".")
+		accountID := splits[0]
+		region := splits[3]
+		req := connect.NewRequest(&porterv1.AssumeRoleCredentialsRequest{
+			ProjectId:    int64(r.ProjectID),
+			AwsAccountId: accountID,
+		})
+		creds, err := conf.ClusterControlPlaneClient.AssumeRoleCredentials(ctx, req)
+		if err != nil {
+			return fmt.Errorf("error getting capi credentials for repository: %w", err)
+		}
+		aws := &ints.AWSIntegration{
+			AWSAccessKeyID:     []byte(creds.Msg.AwsAccessId),
+			AWSSecretAccessKey: []byte(creds.Msg.AwsSecretKey),
+			AWSSessionToken:    []byte(creds.Msg.AwsSessionToken),
+			AWSRegion:          region,
+		}
+		return r.createECRRepository(aws, name)
 	}
 
 	// otherwise, no-op
@@ -735,17 +800,9 @@ func (r *Registry) CreateRepository(
 }
 
 func (r *Registry) createECRRepository(
-	repo repository.Repository,
+	aws *ints.AWSIntegration,
 	name string,
 ) error {
-	aws, err := repo.AWSIntegration().ReadAWSIntegration(
-		r.ProjectID,
-		r.AWSIntegrationID,
-	)
-	if err != nil {
-		return err
-	}
-
 	sess, err := aws.GetSession()
 	if err != nil {
 		return err

+ 25 - 1
zarf/helm/.serverenv

@@ -1,8 +1,32 @@
 # Fill out this file, and renamed to '.server.env' in order to run this with Tilt
+
+# Required parameters
 SQL_LITE=false
 DB_NAME=porter
 DB_USER=porter
 DB_PASSWORD=porter
 DB_HOST=postgresql
 DB_PORT=5432
-CLUSTER_CONTROL_PLANE_ADDRESS=http://ccp-web:7833
+
+# Required for accessing cluster control plane. If ENABLE_CAPI_PROVISIONER=false, nothing in this section will be used
+ENABLE_CAPI_PROVISIONER=false
+NATS_URL=nats:4222
+CLUSTER_CONTROL_PLANE_ADDRESS=http://ccp-web:7833
+
+# Github Login OAuth
+GITHUB_LOGIN_ENABLED=false
+GITHUB_CLIENT_ID=<your_github_client_id.Required_if_GITHUB_LOGIN_ENABLED=true>
+GITHUB_CLIENT_SECRET=<your_github_client_secret.Required_if_GITHUB_LOGIN_ENABLED=true>
+
+# Github App for repo deployments, and preview environments. Remove these if you are not using preview environments or deploying from a repo locally
+GITHUB_APP_CLIENT_ID=<github_app_id>
+GITHUB_APP_CLIENT_SECRET=<github_secret>
+GITHUB_APP_WEBHOOK_SECRET=<webhook_secret>
+GITHUB_APP_NAME=<github_app_name>
+GITHUB_APP_ID=<github_app_id>
+# GITHUB_APP_SECRET_PATH is the path to your secret within the container. Tilt will sync your ~/.ssh/ folder into /app/ssh automatically. This will likely be /app/ssh/your_ssh_pem_name
+GITHUB_APP_SECRET_PATH=<path_to_secret>
+
+# Optional parameters
+HELM_APP_REPO_URL=https://charts.getporter.dev
+HELM_ADD_ON_REPO_URL=https://charts.getporter.dev

+ 17 - 37
zarf/helm/kustomization.yaml

@@ -6,16 +6,10 @@ helmCharts:
   repo: https://charts.getporter.dev
   releaseName: porter-server
   valuesFile: server.yaml
-# - name: web
-#   repo: https://charts.getporter.dev
-#   releaseName: porter-dashboard
-#   valuesFile: dashboard.yaml
 
 configMapGenerator:
 - name: porter-server-env
   env: .server.env
-# - name: porter-dashboard-env
-  # env: .dashboard.env
 generatorOptions:
   disableNameSuffixHash: true
 
@@ -33,34 +27,20 @@ patchesStrategicMerge:
           envFrom:
           - configMapRef: 
               name: porter-server-env
-# - |-
-#   apiVersion: apps/v1
-#   kind: Deployment
-#   metadata:
-#     name: porter-dashboard-web
-#   spec:
-#     template:
-#       spec:
-#         containers:
-#         - name: web
-#           envFrom:
-#           - configMapRef: 
-#               name: porter-dashboard-env
-# - |-
-#   apiVersion: apps/v1
-#   kind: Deployment
-#   metadata:
-#     name: porter-dashboard-web
-#   spec:
-#     template:
-#       spec:
-#         volumes:
-#         - name: hot-reload
-#           hostPath:
-#             path: /host/porter/dashboard
-#             type: ''
-#         containers:
-#         - name: web
-#           volumeMounts:
-#           - name: hot-reload
-#             mountPath: /app
+- |-
+  apiVersion: apps/v1
+  kind: Deployment
+  metadata:
+    name: porter-server-web
+  spec:
+    template:
+      spec:
+        containers:
+        - name: web
+          volumeMounts:
+          - mountPath: /app/ssh
+            name: ssh-keys
+        volumes:
+        - name: ssh-keys
+          hostPath:
+            path: /local-user/.ssh