Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support encrypted s3 bucket for plan uploads #1882

Merged
merged 1 commit into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ inputs:
upload-plan-destination-s3-bucket:
description: Name of the destination bucket for AWS S3. Should be provided if destination == aws
required: false
upload-plan-destination-s3-encryption-enabled:
description: If encryption is to be enabled for s3 bucket
required: false
default: "false"
upload-plan-destination-s3-encryption-type:
description: the type of encryption to use for the S3 bucket, either AES256 or KMS
required: false
default: "AES256"
upload-plan-destination-s3-encryption-kms-key-id:
description: for encryption of type KMS you need to specify the KMS key ID to use
required: false

upload-plan-destination-gcp-bucket:
description: Name of the destination bucket for a GCP bucket. Should be provided if destination == gcp
required: false
Expand Down Expand Up @@ -367,6 +379,9 @@ runs:
shell: bash
env:
PLAN_UPLOAD_DESTINATION: ${{ inputs.upload-plan-destination }}
PLAN_UPLOAD_S3_ENCRYPTION_ENABLED: ${{ inputs.upload-plan-destination-s3-encryption-enabled }}
PLAN_UPLOAD_S3_ENCRYPTION_TYPE: ${{ inputs.upload-plan-destination-s3-encryption-type }}
PLAN_UPLOAD_S3_ENCRYPTION_KMS_ID: ${{ inputs.upload-plan-destination-s3-encryption-kms-key-id }}
GOOGLE_STORAGE_LOCK_BUCKET: ${{ inputs.google-lock-bucket }}
GOOGLE_STORAGE_PLAN_ARTEFACT_BUCKET: ${{ inputs.upload-plan-destination-gcp-bucket }}
AWS_S3_BUCKET: ${{ inputs.upload-plan-destination-s3-bucket }}
Expand Down Expand Up @@ -404,6 +419,9 @@ runs:
env:
actionref: ${{ github.action_ref }}
PLAN_UPLOAD_DESTINATION: ${{ inputs.upload-plan-destination }}
PLAN_UPLOAD_S3_ENCRYPTION_ENABLED: ${{ inputs.upload-plan-destination-s3-encryption-enabled }}
PLAN_UPLOAD_S3_ENCRYPTION_TYPE: ${{ inputs.upload-plan-destination-s3-encryption-type }}
PLAN_UPLOAD_S3_ENCRYPTION_KMS_ID: ${{ inputs.upload-plan-destination-s3-encryption-kms-key-id }}
GOOGLE_STORAGE_LOCK_BUCKET: ${{ inputs.google-lock-bucket }}
GOOGLE_STORAGE_PLAN_ARTEFACT_BUCKET: ${{ inputs.upload-plan-destination-gcp-bucket }}
AWS_S3_BUCKET: ${{ inputs.upload-plan-destination-s3-bucket }}
Expand Down
56 changes: 53 additions & 3 deletions libs/storage/aws_plan_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,53 @@ type S3Client interface {
DeleteObject(ctx context.Context, params *s3.DeleteObjectInput, optFns ...func(*s3.Options)) (*s3.DeleteObjectOutput, error)
}

type AwsS3EncryptionType string

const (
ServerSideEncryptionAes256 AwsS3EncryptionType = "AES256"
ServerSideEncryptionAwsKms AwsS3EncryptionType = "aws:kms"
)

type PlanStorageAWS struct {
Client S3Client
Bucket string
Context context.Context
Client S3Client
Bucket string
Context context.Context
EncryptionEnabled bool
EncryptionType AwsS3EncryptionType
KMSEncryptionId string
}

func NewAWSPlanStorage(bucketName string, encryptionEnabled bool, encryptionType string, KMSEncryptionId string) (*PlanStorageAWS, error) {
if bucketName == "" {
return nil, fmt.Errorf("AWS_S3_BUCKET is not defined")
}
ctx, client, err := GetAWSStorageClient()
if err != nil {
return nil, fmt.Errorf("could not retrieve aws storage client")
}
planStorage := &PlanStorageAWS{
Context: ctx,
Client: client,
Bucket: bucketName,
}
if encryptionEnabled {
planStorage.EncryptionEnabled = true
if encryptionType == "AES256" {
planStorage.EncryptionType = ServerSideEncryptionAes256
} else if encryptionType == "KMS" {
if KMSEncryptionId == "" {
return nil, fmt.Errorf("KMS encryption requested but no KMS key specified")
}
planStorage.EncryptionType = ServerSideEncryptionAwsKms
planStorage.KMSEncryptionId = KMSEncryptionId
} else {
return nil, fmt.Errorf("unknown encryption type specified for aws plan bucket: %v", encryptionType)
}
}

return planStorage, nil

}
func (psa *PlanStorageAWS) PlanExists(artifactName, storedPlanFilePath string) (bool, error) {
input := &s3.HeadObjectInput{
Bucket: aws.String(psa.Bucket),
Expand Down Expand Up @@ -59,6 +100,15 @@ func (psa *PlanStorageAWS) StorePlanFile(fileContents []byte, artifactName, file
Bucket: aws.String(psa.Bucket),
Key: aws.String(fileName),
}

// support for encryption
if psa.EncryptionEnabled {
input.ServerSideEncryption = types.ServerSideEncryption(psa.EncryptionType)
if psa.EncryptionType == ServerSideEncryptionAwsKms {
input.SSEKMSKeyId = aws.String(psa.KMSEncryptionId)
}
}

_, err := psa.Client.PutObject(psa.Context, input)
if err != nil {
log.Printf("Failed to write file to bucket: %v", err)
Expand Down
18 changes: 7 additions & 11 deletions libs/storage/plan_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,18 +235,14 @@ func NewPlanStorage(ghToken string, ghRepoOwner string, ghRepositoryName string,
Context: ctx,
}
case uploadDestination == "aws":
ctx, client, err := GetAWSStorageClient()
if err != nil {
return nil, fmt.Errorf(fmt.Sprintf("Failed to create AWS storage client: %s", err))
}
bucketName := strings.ToLower(os.Getenv("AWS_S3_BUCKET"))
if bucketName == "" {
return nil, fmt.Errorf("AWS_S3_BUCKET is not defined")
}
planStorage = &PlanStorageAWS{
Context: ctx,
Client: client,
Bucket: bucketName,
encryptionEnabled := os.Getenv("PLAN_UPLOAD_S3_ENCRYPTION_ENABLED") == "true"
encryptionType := os.Getenv("PLAN_UPLOAD_S3_ENCRYPTION_TYPE")
encryptionKmsId := os.Getenv("PLAN_UPLOAD_S3_ENCRYPTION_KMS_ID")
var err error
planStorage, err = NewAWSPlanStorage(bucketName, encryptionEnabled, encryptionType, encryptionKmsId)
if err != nil {
return nil, fmt.Errorf("error while creating AWS plan storage: %v", err)
}
case uploadDestination == "gitlab":
//TODO implement me
Expand Down
Loading