From 7ffcc6798f1afaf0535bbd14165ce2cb3a05d566 Mon Sep 17 00:00:00 2001 From: Kenneth Yang Date: Tue, 13 Jun 2023 08:51:43 -0700 Subject: [PATCH] v0.0.1-beta (#3) * v0.0.1-beta --- Makefile | 4 +- config/config.primary.development.aws.yml | 2 +- db/migration/000001_init_schema.up.sql | 78 +++++++++---------- docs/CONFIGURATION.md | 18 +++++ docs/GETTING_STARTED.md | 5 +- docs/PRODUCTION_DEPLOYMENT.md | 22 ++++-- examples/Dockerfile | 2 +- .../config/config.primary.development.aws.yml | 2 +- internal/attestor/aws_iid/iid.go | 6 -- internal/authentication/authentication.go | 2 +- internal/client/acmpca/issue.go | 3 - internal/config/fx.go | 4 +- internal/config/path.go | 5 +- internal/v1/accounts/service.go | 2 +- internal/v1/certificate/operations.go | 6 -- internal/v1/certificate/sign_test.go | 2 - 16 files changed, 91 insertions(+), 72 deletions(-) diff --git a/Makefile b/Makefile index 97bcde0..efdc02c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,4 @@ SERVICE := baseca -VERSION := $(shell git describe --tags) BUILD := $(shell git rev-parse --short HEAD) GITHUB_REPO := github.com/coinbase/baseca @@ -14,7 +13,6 @@ usage: .PHONY: info info: @ echo SERVICE: $(SERVICE) - @ echo VERSION: $(VERSION) @ echo BUILD: $(BUILD) .PHONY: clean @@ -36,7 +34,7 @@ build: info clean .PHONY: postgres postgres: - @ docker run --name baseca -p 5432:5432 -v ${pwd)/db/init:/db/init -e POSTGRES_USER=root -e POSTGRES_PASSWORD=secret -d postgres:latest + @ docker run --name baseca -p 5432:5432 -v /path/to/baseca/db/init:/db/init -e POSTGRES_USER=root -e POSTGRES_PASSWORD=secret -d postgres:latest .PHONY: createdb createdb: diff --git a/config/config.primary.development.aws.yml b/config/config.primary.development.aws.yml index f659dad..c3fdf9a 100644 --- a/config/config.primary.development.aws.yml +++ b/config/config.primary.development.aws.yml @@ -27,7 +27,7 @@ acm_pca: root_ca: false development_usw1: region: us-west-1 - ca_arn: arn:aws:acm-pca:us-west-1:123456789012:certificate-authority/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + ca_arn: arn:aws:acm-pca:us-west-1:123456789012:certificate-authority/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy ca_active_day: 90 assume_role: false diff --git a/db/migration/000001_init_schema.up.sql b/db/migration/000001_init_schema.up.sql index b25ea29..c7190f4 100644 --- a/db/migration/000001_init_schema.up.sql +++ b/db/migration/000001_init_schema.up.sql @@ -1,70 +1,70 @@ CREATE TABLE "users" ( "uuid" uuid UNIQUE PRIMARY KEY, - "username" varchar UNIQUE NOT NULL, - "hashed_credential" varchar NOT NULL, - "full_name" varchar NOT NULL, - "email" varchar UNIQUE NOT NULL, - "permissions" varchar NOT NULL, + "username" varchar(100) UNIQUE NOT NULL, + "hashed_credential" varchar(100) NOT NULL, + "full_name" varchar(100) NOT NULL, + "email" varchar(100) UNIQUE NOT NULL, + "permissions" varchar(100) NOT NULL, "credential_changed_at" timestamptz NOT NULL DEFAULT '0001-01-01 00:00:00Z', "created_at" timestamptz NOT NULL DEFAULT (now()) ); CREATE TABLE "accounts" ( "client_id" uuid UNIQUE PRIMARY KEY, - "api_token" varchar NOT NULL, - "service_account" varchar NOT NULL, - "environment" varchar NOT NULL, - "team" varchar NOT NULL, - "email" varchar NOT NULL, - "regular_expression" varchar, - "valid_subject_alternate_name" varchar[] NOT NULL, - "valid_certificate_authorities" varchar[] NOT NULL, - "extended_key" varchar NOT NULL, + "api_token" varchar(100) NOT NULL, + "service_account" varchar(100) NOT NULL, + "environment" varchar(100) NOT NULL, + "team" varchar(100) NOT NULL, + "email" varchar(100) NOT NULL, + "regular_expression" varchar(100), + "valid_subject_alternate_name" varchar(100)[] NOT NULL, + "valid_certificate_authorities" varchar(100)[] NOT NULL, + "extended_key" varchar(100) NOT NULL, "certificate_validity" smallserial NOT NULL, - "subordinate_ca" varchar NOT NULL, - "node_attestation" varchar[], + "subordinate_ca" varchar(100) NOT NULL, + "node_attestation" varchar(100)[], "created_at" timestamptz NOT NULL DEFAULT (now()), "created_by" uuid NOT NULL ); CREATE TABLE "certificates" ( - "serial_number" varchar PRIMARY KEY, - "account" varchar NOT NULL, - "environment" varchar NOT NULL, - "extended_key" varchar NOT NULL, - "common_name" varchar NOT NULL, - "subject_alternative_name" varchar[] NOT NULL, + "serial_number" varchar(100) PRIMARY KEY, + "account" varchar(100) NOT NULL, + "environment" varchar(100) NOT NULL, + "extended_key" varchar(100) NOT NULL, + "common_name" varchar(100) NOT NULL, + "subject_alternative_name" varchar(100)[] NOT NULL, "expiration_date" timestamptz NOT NULL DEFAULT (now()), "issued_date" timestamptz NOT NULL DEFAULT (now()), "revoked" boolean NOT NULL DEFAULT false, - "revoked_by" varchar, + "revoked_by" varchar(100), "revoke_date" timestamptz, - "certificate_authority_arn" varchar + "certificate_authority_arn" varchar(100) ); CREATE TABLE "aws_attestation" ( "client_id" uuid UNIQUE PRIMARY KEY, - "role_arn" varchar, - "assume_role" varchar, - "security_group_id" varchar[], - "region" varchar, - "instance_id" varchar, - "image_id" varchar, + "role_arn" varchar(100), + "assume_role" varchar(100), + "security_group_id" varchar(100)[], + "region" varchar(100), + "instance_id" varchar(100), + "image_id" varchar(100), "instance_tags" json ); CREATE TABLE "provisioners" ( "client_id" uuid UNIQUE PRIMARY KEY, - "api_token" varchar NOT NULL, - "provisioner_account" varchar NOT NULL, - "environments" varchar[] NOT NULL, - "team" varchar NOT NULL, - "email" varchar NOT NULL, - "regular_expression" varchar, - "valid_subject_alternate_names" varchar[] NOT NULL, - "extended_keys" varchar[] NOT NULL, + "api_token" varchar(100) NOT NULL, + "provisioner_account" varchar(100) NOT NULL, + "environments" varchar(100)[] NOT NULL, + "team" varchar(100) NOT NULL, + "email" varchar(100) NOT NULL, + "regular_expression" varchar(100), + "valid_subject_alternate_names" varchar(100)[] NOT NULL, + "extended_keys" varchar(100)[] NOT NULL, "max_certificate_validity" smallserial NOT NULL, - "node_attestation" varchar[], + "node_attestation" varchar(100)[], "created_at" timestamptz NOT NULL DEFAULT (now()), "created_by" uuid NOT NULL ); diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index f2039a2..4b6979a 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -1,3 +1,21 @@ +# `baseca` Configuration File + +## Environment Variables + +Configurations are held the [`baseca/config`](../config/). The structure for the configuration files are `config.primary.CONFIGURATION.ENVIRONMENT.yml`. + +- If `ENVIRONMENT` is set to anything the value will be `aws`, if it is not set it will be `sandbox`. +- If `CONFIGURATION` is set, that same value will reflect within the configuration file. + +If `baseca` is run with the following environment variables then during start time it will look for the `config.primary.infrastructure-production.aws.yml` configuration file. + +```sh +export ENVIRONMENT=production +export CONFIGURATION=infrastructure-production +``` + +## Configuration File Parameters + ```yml grpc_server_address: 0.0.0.0:9090 # baseca gRPC Server Port diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index b9dffdd..a4a1ed9 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -168,8 +168,11 @@ Run the `baseca` Container **NOTE:** You must have AWS credentials stored locally within `~/.aws` with permissions to all infrastructure components created from Terraform and access to the Private CAs. +**RELEASE:** Search for Latest [`baseca ghcr.io Published Release`](https://github.com/orgs/coinbase/packages/container/package/baseca) and update the `VERSION_SHA` container tag with the latest version. + ```sh -docker run -p 9090:9090 -e password=secret -v ~/.aws/:/home/baseca/.aws/:ro -v $(pwd)/config:/home/baseca/config ghcr.io/coinbase/baseca:v0.0.1-beta +docker run -p 9090:9090 -e password=secret -v ~/.aws/:/home/baseca/.aws/:ro \ + -v /path/to/baseca/config:/home/baseca/config ghcr.io/coinbase/baseca:VERSION_SHA ``` ### 3b. Compile `baseca` as Executable (Option B) diff --git a/docs/PRODUCTION_DEPLOYMENT.md b/docs/PRODUCTION_DEPLOYMENT.md index 032dc2e..89f27ff 100644 --- a/docs/PRODUCTION_DEPLOYMENT.md +++ b/docs/PRODUCTION_DEPLOYMENT.md @@ -188,22 +188,28 @@ psql -h [rds_writer_endpoint] -U [username] -d baseca -f /path/to/init.sql ## Build and Upload `baseca` to ECR -### Option A: Build from Published `baseca` Image +### 1a. Build from Published `baseca` Image _Use this option by using the published image from `baseca` without any code changes or updates to your Dockerfile._ Create `Dockerfile` and Copy [`Configurations`](../config) to `/home/baseca/config` within the Docker Container. +**RELEASE:** Search for Latest [`baseca ghcr.io Published Release`](https://github.com/orgs/coinbase/packages/container/package/baseca) and update the `VERSION_SHA` container tag with the latest version. + ```Dockerfile -FROM ghcr.io/coinbase/baseca:v0.0.1-beta +# baseca/Dockerfile-production + +FROM ghcr.io/coinbase/baseca:VERSION_SHA COPY ./config /home/baseca/config +USER baseca + CMD ["/home/baseca/baseca"] ``` ```sh -cd /path/to/Dockerfile -docker build -t baseca . +cd /path/to/baseca/Dockerfile-production +docker build -t baseca -f Dockerfile-production . ``` Push Image to ECR Registry @@ -218,14 +224,20 @@ docker push .dkr.ecr..amazonaws.com/baseca:latest -### Option B: Local Build +### 1b. Local Build _Use this option if you have requirements to change the `baseca` image through either custom code changes or updates to the Dockerfile._ +**NOTE:** If you intend to run a local build, within the current [`Dockerfile`](../Dockerfile) we do not copy the `config/` directory into the base image. Additionally within `.dockerignore` we ignore the `config/` directory as well. If you are running the image directly, the OS directory structure for the final image should be the same as the image in the previous option. + ```sh cd /path/to/baseca docker build -t baseca . +``` + +Push Image to ECR Registry +```sh docker tag baseca .dkr.ecr..amazonaws.com/baseca:latest aws ecr get-login-password --region | docker login --username AWS --password-stdin .dkr.ecr..amazonaws.com docker push .dkr.ecr..amazonaws.com/baseca:latest diff --git a/examples/Dockerfile b/examples/Dockerfile index ef64aad..e1a9e91 100644 --- a/examples/Dockerfile +++ b/examples/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/coinbase/baseca:v0.0.1-beta +FROM ghcr.io/coinbase/baseca:sha-xxxxx COPY ./config /home/baseca/config USER baseca diff --git a/examples/config/config.primary.development.aws.yml b/examples/config/config.primary.development.aws.yml index f659dad..c3fdf9a 100644 --- a/examples/config/config.primary.development.aws.yml +++ b/examples/config/config.primary.development.aws.yml @@ -27,7 +27,7 @@ acm_pca: root_ca: false development_usw1: region: us-west-1 - ca_arn: arn:aws:acm-pca:us-west-1:123456789012:certificate-authority/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + ca_arn: arn:aws:acm-pca:us-west-1:123456789012:certificate-authority/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy ca_active_day: 90 assume_role: false diff --git a/internal/attestor/aws_iid/iid.go b/internal/attestor/aws_iid/iid.go index d8a502e..8ef18db 100644 --- a/internal/attestor/aws_iid/iid.go +++ b/internal/attestor/aws_iid/iid.go @@ -195,12 +195,6 @@ func getEC2Instance(instancesDesc *ec2.DescribeInstancesOutput) (ec2types.Instan return instancesDesc.Reservations[0].Instances[0], nil } -func isEmptyAWSIID(iid types.AWSInstanceIdentityDocument) bool { - return iid.RoleArn == "" && iid.AssumeRole == "" && len(iid.SecurityGroups) == 0 && - iid.Region == "" && iid.InstanceID == "" && iid.ImageID == "" && - len(iid.InstanceTags) == 0 -} - func GetNodeAttestation(node_attestation *apiv1.NodeAttestation) []string { var valid_attestation []string var iid = node_attestation.AwsIid diff --git a/internal/authentication/authentication.go b/internal/authentication/authentication.go index c42f964..ecbb9c1 100644 --- a/internal/authentication/authentication.go +++ b/internal/authentication/authentication.go @@ -9,7 +9,7 @@ import ( ) func HashPassword(password string) (string, error) { - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 15) if err != nil { return "", fmt.Errorf("failed to hash password %w", err) } diff --git a/internal/client/acmpca/issue.go b/internal/client/acmpca/issue.go index 940e8d2..2740826 100644 --- a/internal/client/acmpca/issue.go +++ b/internal/client/acmpca/issue.go @@ -18,9 +18,6 @@ import ( const ( _subordinateCACertificate_PathLen0_V1 = "arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen0/V1" - _codeSigningCertifiate_V1 = "arn:aws:acm-pca:::template/CodeSigningCertifiate/V1" - _endEntityServerAuthCertificate_V1 = "arn:aws:acm-pca:::template/EndEntityServerAuthCertificate/V1" - _endEntityClientAuthCertificate_V1 = "arn:aws:acm-pca:::template/EndEntityClientAuthCertificate/V1" ) func (c *PrivateCaClient) IssueCertificateFromTemplate(parameters *apiv1.CertificateAuthorityParameter, csr []byte, template string) (*x509.Certificate, error) { diff --git a/internal/config/fx.go b/internal/config/fx.go index a0e55a2..b74f221 100644 --- a/internal/config/fx.go +++ b/internal/config/fx.go @@ -1,6 +1,8 @@ package config import ( + "log" + "github.com/coinbase/baseca/internal/environment" "github.com/coinbase/baseca/internal/logger" "go.uber.org/fx" @@ -41,7 +43,7 @@ func ProvideConfig(p Parameter) (Result, error) { _, resolver := p.Environment, p.PathResolver path, err := resolver.Resolve() if err != nil { - ctxLogger.Error(err.Error()) + log.Fatalf("configuration file does not exist [%s]", err.Error()) } ctxLogger.Info("Load Config From File, Config Path: " + path) v, err := BuildViper(path) diff --git a/internal/config/path.go b/internal/config/path.go index 5f66ea0..03c0420 100644 --- a/internal/config/path.go +++ b/internal/config/path.go @@ -29,7 +29,10 @@ var _ ConfigFilePathResolver = (*Resolver)(nil) func (r Resolver) Resolve() (string, error) { configurationFileName := configurationFileName(r.Environment) location := fmt.Sprintf(r.Template, configurationFileName) - path, _ := bazel.Runfile(location) + path, err := bazel.Runfile(location) + if err != nil { + return "", fmt.Errorf(location) + } return path, nil } diff --git a/internal/v1/accounts/service.go b/internal/v1/accounts/service.go index 59983b7..b635c68 100644 --- a/internal/v1/accounts/service.go +++ b/internal/v1/accounts/service.go @@ -66,7 +66,7 @@ func (s *Service) CreateServiceAccount(ctx context.Context, req *apiv1.CreateSer payload, ok := ctx.Value(types.AuthorizationPayloadKey).(*authentication.Claims) if !ok { - logger.RpcError(status.Error(codes.Internal, "internal server error"), fmt.Errorf("service auth context missing")) + return nil, logger.RpcError(status.Error(codes.Internal, "internal server error"), fmt.Errorf("service auth context missing")) } // Production Service Accounts Require Attestation diff --git a/internal/v1/certificate/operations.go b/internal/v1/certificate/operations.go index ec1018a..d4efbbb 100644 --- a/internal/v1/certificate/operations.go +++ b/internal/v1/certificate/operations.go @@ -31,12 +31,6 @@ var ( "KEY_COMPROMISE", "CERTIFICATE_AUTHORITY_COMPROMISE", } - - _validTemplates = []string{ - "arn:aws:acm-pca:::template/CodeSigningCertificate/V1", - "arn:aws:acm-pca:::template/EndEntityClientAuthCertificate/V1", - "arn:aws:acm-pca:::template/EndEntityServerAuthCertificate/V1", - } ) func (c *Certificate) RevokeCertificate(ctx context.Context, req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) { diff --git a/internal/v1/certificate/sign_test.go b/internal/v1/certificate/sign_test.go index 96a0882..41d8fdc 100644 --- a/internal/v1/certificate/sign_test.go +++ b/internal/v1/certificate/sign_test.go @@ -3,7 +3,6 @@ package certificate import ( "context" "crypto/x509" - "fmt" "testing" "github.com/coinbase/baseca/db/mock" @@ -73,7 +72,6 @@ func TestSignCSR(t *testing.T) { req := tc.req() res, err := c.SignCSR(ctx, req) - fmt.Println(err) tc.check(t, res, err) }) }