Skip to content

Commit 71e04a4

Browse files
authored
Merge pull request #38 from buildkite/keithduncan/fix-cross-region
Use current region to find bucket region
2 parents 67c4e22 + 5daa8ac commit 71e04a4

File tree

3 files changed

+55
-23
lines changed

3 files changed

+55
-23
lines changed

s3secrets-helper/main.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ const (
1616
envPipeline = "BUILDKITE_PIPELINE_SLUG"
1717
envRepo = "BUILDKITE_REPO"
1818
envCredHelper = "BUILDKITE_PLUGIN_S3_SECRETS_CREDHELPER"
19-
20-
envDefaultRegion = "AWS_DEFAULT_REGION"
21-
defaultRegion = "us-east-1"
2219
)
2320

2421
func main() {
@@ -42,11 +39,7 @@ func mainWithError(log *log.Logger) error {
4239
return fmt.Errorf("%s or %s required", envPrefix, envPipeline)
4340
}
4441

45-
region := os.Getenv(envDefaultRegion)
46-
if region == "" {
47-
region = defaultRegion
48-
}
49-
client, err := s3.New(region)
42+
client, err := s3.New(log, bucket)
5043
if err != nil {
5144
return err
5245
}

s3secrets-helper/s3/s3.go

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,76 @@
11
package s3
22

33
import (
4+
"log"
45
"io/ioutil"
6+
"os"
57

68
"github.com/aws/aws-sdk-go/aws"
79
"github.com/aws/aws-sdk-go/aws/awserr"
10+
"github.com/aws/aws-sdk-go/aws/ec2metadata"
811
"github.com/aws/aws-sdk-go/aws/session"
912
"github.com/aws/aws-sdk-go/service/s3"
13+
"github.com/aws/aws-sdk-go/service/s3/s3manager"
1014
"github.com/buildkite/elastic-ci-stack-s3-secrets-hooks/s3secrets-helper/v2/sentinel"
1115
)
1216

17+
const envDefaultRegion = "AWS_DEFAULT_REGION"
18+
1319
type Client struct {
1420
s3 *s3.S3
21+
bucket string
1522
}
1623

17-
func New(region string) (*Client, error) {
18-
sess, err := session.NewSession(&aws.Config{
19-
Region: &region,
24+
func New(log *log.Logger, bucket string) (*Client, error) {
25+
sess, err := session.NewSession()
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
currentRegion := os.Getenv(envDefaultRegion)
31+
// Discover our executing region using the IMDS
32+
if currentRegion == "" {
33+
idms := ec2metadata.New(sess)
34+
currentRegion, _ = idms.Region()
35+
}
36+
// Fall back to us-east-1 :(
37+
if currentRegion == "" {
38+
currentRegion = "us-east-1"
39+
}
40+
41+
log.Printf("Discovered current region as %q\n", currentRegion)
42+
43+
// Using the current region (or a guess) find where the bucket lives
44+
bucketRegion, err := s3manager.GetBucketRegion(aws.BackgroundContext(), sess, bucket, currentRegion)
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
log.Printf("Discovered bucket region as %q\n", bucketRegion)
50+
51+
sess, err = session.NewSession(&aws.Config{
52+
Region: &bucketRegion,
2053
})
2154
if err != nil {
2255
return nil, err
2356
}
2457
return &Client{
2558
s3: s3.New(sess),
59+
bucket: bucket,
2660
}, nil
2761
}
2862

63+
func (c *Client) Bucket() (string) {
64+
return c.bucket
65+
}
66+
2967
// Get downloads an object from S3.
3068
// Intended for small files; object is fully read into memory.
3169
// sentinel.ErrNotFound and sentinel.ErrForbidden are returned for those cases.
3270
// Other errors are returned verbatim.
33-
func (c *Client) Get(bucket, key string) ([]byte, error) {
71+
func (c *Client) Get(key string) ([]byte, error) {
3472
out, err := c.s3.GetObject(&s3.GetObjectInput{
35-
Bucket: &bucket,
73+
Bucket: &c.bucket,
3674
Key: &key,
3775
})
3876
if err != nil {
@@ -59,8 +97,8 @@ func (c *Client) Get(bucket, key string) ([]byte, error) {
5997
// 200 OK returns true without error.
6098
// 404 Not Found and 403 Forbidden return false without error.
6199
// Other errors result in false with an error.
62-
func (c *Client) BucketExists(bucket string) (bool, error) {
63-
if _, err := c.s3.HeadBucket(&s3.HeadBucketInput{Bucket: &bucket}); err != nil {
100+
func (c *Client) BucketExists() (bool, error) {
101+
if _, err := c.s3.HeadBucket(&s3.HeadBucketInput{Bucket: &c.bucket}); err != nil {
64102
if aerr, ok := err.(awserr.Error); ok {
65103
switch aerr.Code() {
66104
// https://github.com/aws/aws-sdk-go/issues/2593#issuecomment-491436818

s3secrets-helper/secrets/secrets.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import (
1212

1313
// Client represents interaction with AWS S3
1414
type Client interface {
15-
Get(bucket, key string) ([]byte, error)
16-
BucketExists(bucket string) (bool, error)
15+
Bucket() (string)
16+
Get(key string) ([]byte, error)
17+
BucketExists() (bool, error)
1718
}
1819

1920
// Agent represents interaction with an ssh-agent process
@@ -56,12 +57,12 @@ type Config struct {
5657
// functionality; secrets are downloaded from S3, and loaded into ssh-agent
5758
// etc.
5859
func Run(conf Config) error {
59-
bucket := conf.Bucket
60+
bucket := conf.Client.Bucket()
6061
log := conf.Logger
6162

6263
log.Printf("~~~ Downloading secrets from :s3: %s", bucket)
6364

64-
if ok, err := conf.Client.BucketExists(bucket); !ok {
65+
if ok, err := conf.Client.BucketExists(); !ok {
6566
if err != nil {
6667
log.Printf("+++ :warning: Bucket %q not found: %v", bucket, err)
6768
} else {
@@ -102,7 +103,7 @@ func getSSHKeys(conf Config, results chan<- getResult) {
102103
for _, k := range keys {
103104
conf.Logger.Printf("- %s", k)
104105
}
105-
go GetAll(conf.Client, conf.Bucket, keys, results)
106+
go GetAll(conf.Client, conf.Client.Bucket(), keys, results)
106107
}
107108

108109
func getEnvs(conf Config, results chan<- getResult) {
@@ -116,7 +117,7 @@ func getEnvs(conf Config, results chan<- getResult) {
116117
for _, k := range keys {
117118
conf.Logger.Printf("- %s", k)
118119
}
119-
go GetAll(conf.Client, conf.Bucket, keys, results)
120+
go GetAll(conf.Client, conf.Client.Bucket(), keys, results)
120121
}
121122

122123
func getGitCredentials(conf Config, results chan<- getResult) {
@@ -128,7 +129,7 @@ func getGitCredentials(conf Config, results chan<- getResult) {
128129
for _, k := range keys {
129130
conf.Logger.Printf("- %s", k)
130131
}
131-
go GetAll(conf.Client, conf.Bucket, keys, results)
132+
go GetAll(conf.Client, conf.Client.Bucket(), keys, results)
132133
}
133134

134135
func handleSSHKeys(conf Config, results <-chan getResult) error {
@@ -241,7 +242,7 @@ func GetAll(c Client, bucket string, keys []string, results chan<- getResult) {
241242
// goroutine immediately fetches from S3, then waits for its turn to send
242243
// to the results channel; concurrent fetch, ordered results.
243244
go func(k string, link <-chan chan<- getResult, nextLink chan<- chan<- getResult) {
244-
data, err := c.Get(bucket, k)
245+
data, err := c.Get(k)
245246
results := <-link // wait for results channel from previous goroutine
246247
results <- getResult{bucket: bucket, key: k, data: data, err: err}
247248
nextLink <- results // send results channel to the next goroutine

0 commit comments

Comments
 (0)