mirror of
https://github.com/grafana/grafana.git
synced 2024-12-02 05:29:42 -06:00
145 lines
4.0 KiB
Go
145 lines
4.0 KiB
Go
package imguploader
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/client"
|
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
|
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
|
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
|
|
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
|
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
|
"github.com/aws/aws-sdk-go/service/sts"
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/util"
|
|
)
|
|
|
|
type S3Uploader struct {
|
|
endpoint string
|
|
region string
|
|
bucket string
|
|
path string
|
|
acl string
|
|
secretKey string
|
|
accessKey string
|
|
pathStyleAccess bool
|
|
log log.Logger
|
|
}
|
|
|
|
func NewS3Uploader(endpoint, region, bucket, path, acl, accessKey, secretKey string, pathStyleAccess bool) *S3Uploader {
|
|
return &S3Uploader{
|
|
endpoint: endpoint,
|
|
region: region,
|
|
bucket: bucket,
|
|
path: path,
|
|
acl: acl,
|
|
accessKey: accessKey,
|
|
secretKey: secretKey,
|
|
pathStyleAccess: pathStyleAccess,
|
|
log: log.New("s3uploader"),
|
|
}
|
|
}
|
|
|
|
func (u *S3Uploader) Upload(ctx context.Context, imageDiskPath string) (string, error) {
|
|
sess, err := session.NewSession()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
creds := credentials.NewChainCredentials(
|
|
[]credentials.Provider{
|
|
&credentials.StaticProvider{Value: credentials.Value{
|
|
AccessKeyID: u.accessKey,
|
|
SecretAccessKey: u.secretKey,
|
|
}},
|
|
&credentials.EnvProvider{},
|
|
webIdentityProvider(sess),
|
|
remoteCredProvider(sess),
|
|
})
|
|
cfg := &aws.Config{
|
|
Region: aws.String(u.region),
|
|
Endpoint: aws.String(u.endpoint),
|
|
S3ForcePathStyle: aws.Bool(u.pathStyleAccess),
|
|
Credentials: creds,
|
|
}
|
|
|
|
rand, err := util.GetRandomString(20)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
key := u.path + rand + pngExt
|
|
u.log.Debug("Uploading image to s3.", "bucket", u.bucket, "path", key)
|
|
|
|
// We can ignore the gosec G304 warning on this one because `imageDiskPath` comes
|
|
// from alert notifiers and is only used to upload images generated by alerting.
|
|
// nolint:gosec
|
|
file, err := os.Open(imageDiskPath)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer func() {
|
|
if err := file.Close(); err != nil {
|
|
u.log.Warn("Failed to close file", "path", imageDiskPath, "err", err)
|
|
}
|
|
}()
|
|
|
|
sess, err = session.NewSession(cfg)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
uploader := s3manager.NewUploader(sess)
|
|
result, err := uploader.UploadWithContext(ctx, &s3manager.UploadInput{
|
|
Bucket: aws.String(u.bucket),
|
|
Key: aws.String(key),
|
|
ACL: aws.String(u.acl),
|
|
Body: file,
|
|
ContentType: aws.String("image/png"),
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return result.Location, nil
|
|
}
|
|
|
|
func webIdentityProvider(sess client.ConfigProvider) credentials.Provider {
|
|
svc := sts.New(sess)
|
|
|
|
roleARN := os.Getenv("AWS_ROLE_ARN")
|
|
tokenFilepath := os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")
|
|
roleSessionName := os.Getenv("AWS_ROLE_SESSION_NAME")
|
|
|
|
// nolint:staticcheck
|
|
return stscreds.NewWebIdentityRoleProvider(svc, roleARN, roleSessionName, tokenFilepath)
|
|
}
|
|
|
|
func remoteCredProvider(sess *session.Session) credentials.Provider {
|
|
ecsCredURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
|
|
|
|
if len(ecsCredURI) > 0 {
|
|
return ecsCredProvider(sess, ecsCredURI)
|
|
}
|
|
return ec2RoleProvider(sess)
|
|
}
|
|
|
|
func ecsCredProvider(sess *session.Session, uri string) credentials.Provider {
|
|
const host = `169.254.170.2`
|
|
|
|
d := defaults.Get()
|
|
return endpointcreds.NewProviderClient(
|
|
*d.Config,
|
|
d.Handlers,
|
|
fmt.Sprintf("http://%s%s", host, uri),
|
|
func(p *endpointcreds.Provider) { p.ExpiryWindow = 5 * time.Minute })
|
|
}
|
|
|
|
func ec2RoleProvider(sess client.ConfigProvider) credentials.Provider {
|
|
return &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute}
|
|
}
|