s3.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package s3
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "github.com/aws/aws-sdk-go-v2/aws"
  9. "github.com/aws/aws-sdk-go-v2/credentials"
  10. "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
  11. "github.com/aws/aws-sdk-go-v2/service/s3"
  12. "github.com/aws/aws-sdk-go-v2/service/s3/types"
  13. "github.com/porter-dev/porter/internal/encryption"
  14. "github.com/porter-dev/porter/internal/models"
  15. "github.com/porter-dev/porter/provisioner/integrations/storage"
  16. )
  17. type S3StorageClient struct {
  18. client *s3.Client
  19. bucket string
  20. encryptionKey *[32]byte
  21. }
  22. type S3Options struct {
  23. AWSRegion string
  24. AWSAccessKeyID string
  25. AWSSecretKey string
  26. AWSBucketName string
  27. EncryptionKey *[32]byte
  28. }
  29. func NewS3StorageClient(opts *S3Options) (*S3StorageClient, error) {
  30. awsConf := aws.Config{
  31. Credentials: credentials.NewStaticCredentialsProvider(
  32. opts.AWSAccessKeyID,
  33. opts.AWSSecretKey,
  34. "",
  35. ),
  36. Region: opts.AWSRegion,
  37. }
  38. // TODO: delete this comment by 2023-01-30 if no issues are noticed when creating a new S3 client
  39. // aws-sdk-go used a SharedConfigState: enabled which is no longer available in v2, without specifying the file name
  40. client := s3.NewFromConfig(awsConf)
  41. return &S3StorageClient{
  42. bucket: opts.AWSBucketName,
  43. encryptionKey: opts.EncryptionKey,
  44. client: client,
  45. }, nil
  46. }
  47. func (s *S3StorageClient) WriteFile(infra *models.Infra, name string, fileBytes []byte, shouldEncrypt bool) error {
  48. ctx := context.Background()
  49. body := fileBytes
  50. var err error
  51. if shouldEncrypt {
  52. body, err = encryption.Encrypt(fileBytes, s.encryptionKey)
  53. if err != nil {
  54. return err
  55. }
  56. }
  57. _, err = s.client.PutObject(ctx, &s3.PutObjectInput{
  58. Body: manager.ReadSeekCloser(bytes.NewReader(body)),
  59. Bucket: &s.bucket,
  60. Key: aws.String(getKeyFromInfra(infra, name)),
  61. })
  62. return err
  63. }
  64. func (s *S3StorageClient) WriteFileWithKey(fileBytes []byte, shouldEncrypt bool, key string) error {
  65. ctx := context.Background()
  66. body := fileBytes
  67. var err error
  68. if shouldEncrypt {
  69. body, err = encryption.Encrypt(fileBytes, s.encryptionKey)
  70. if err != nil {
  71. return err
  72. }
  73. }
  74. _, err = s.client.PutObject(ctx, &s3.PutObjectInput{
  75. Body: manager.ReadSeekCloser(bytes.NewReader(body)),
  76. Bucket: &s.bucket,
  77. Key: aws.String(key),
  78. })
  79. return err
  80. }
  81. func (s *S3StorageClient) ReadFile(infra *models.Infra, name string, shouldDecrypt bool) ([]byte, error) {
  82. ctx := context.Background()
  83. output, err := s.client.GetObject(ctx, &s3.GetObjectInput{
  84. Bucket: &s.bucket,
  85. Key: aws.String(getKeyFromInfra(infra, name)),
  86. })
  87. if err != nil {
  88. var nsk *types.NoSuchKey
  89. if errors.As(err, &nsk) {
  90. return nil, storage.FileDoesNotExist
  91. }
  92. return nil, err
  93. }
  94. if shouldDecrypt {
  95. var encryptedData bytes.Buffer
  96. _, err = encryptedData.ReadFrom(output.Body)
  97. if err != nil {
  98. return nil, err
  99. }
  100. data, err := encryption.Decrypt(encryptedData.Bytes(), s.encryptionKey)
  101. if err != nil {
  102. return nil, err
  103. }
  104. return data, nil
  105. } else {
  106. return io.ReadAll(output.Body)
  107. }
  108. }
  109. func (s *S3StorageClient) DeleteFile(infra *models.Infra, name string) error {
  110. ctx := context.Background()
  111. _, err := s.client.DeleteObject(ctx, &s3.DeleteObjectInput{
  112. Bucket: &s.bucket,
  113. Key: aws.String(getKeyFromInfra(infra, name)),
  114. })
  115. if err != nil {
  116. return err
  117. }
  118. return nil
  119. }
  120. func getKeyFromInfra(infra *models.Infra, name string) string {
  121. return fmt.Sprintf("%s/%s", infra.GetUniqueName(), name)
  122. }