mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add credentials endpoint option for awslogs driver
Signed-off-by: Adnan Khan <adnkha@amazon.com>
This commit is contained in:
parent
1e94a4862e
commit
c7cc9d6759
2 changed files with 163 additions and 11 deletions
|
@ -14,6 +14,7 @@ import (
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
|
||||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
@ -26,16 +27,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
name = "awslogs"
|
name = "awslogs"
|
||||||
regionKey = "awslogs-region"
|
regionKey = "awslogs-region"
|
||||||
regionEnvKey = "AWS_REGION"
|
regionEnvKey = "AWS_REGION"
|
||||||
logGroupKey = "awslogs-group"
|
logGroupKey = "awslogs-group"
|
||||||
logStreamKey = "awslogs-stream"
|
logStreamKey = "awslogs-stream"
|
||||||
logCreateGroupKey = "awslogs-create-group"
|
logCreateGroupKey = "awslogs-create-group"
|
||||||
tagKey = "tag"
|
tagKey = "tag"
|
||||||
datetimeFormatKey = "awslogs-datetime-format"
|
datetimeFormatKey = "awslogs-datetime-format"
|
||||||
multilinePatternKey = "awslogs-multiline-pattern"
|
multilinePatternKey = "awslogs-multiline-pattern"
|
||||||
batchPublishFrequency = 5 * time.Second
|
credentialsEndpointKey = "awslogs-credentials-endpoint"
|
||||||
|
batchPublishFrequency = 5 * time.Second
|
||||||
|
|
||||||
// See: http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html
|
// See: http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html
|
||||||
perEventBytes = 26
|
perEventBytes = 26
|
||||||
|
@ -50,6 +52,8 @@ const (
|
||||||
invalidSequenceTokenCode = "InvalidSequenceTokenException"
|
invalidSequenceTokenCode = "InvalidSequenceTokenException"
|
||||||
resourceNotFoundCode = "ResourceNotFoundException"
|
resourceNotFoundCode = "ResourceNotFoundException"
|
||||||
|
|
||||||
|
credentialsEndpoint = "http://169.254.170.2"
|
||||||
|
|
||||||
userAgentHeader = "User-Agent"
|
userAgentHeader = "User-Agent"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -198,6 +202,10 @@ var newRegionFinder = func() regionFinder {
|
||||||
return ec2metadata.New(session.New())
|
return ec2metadata.New(session.New())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newSDKEndpoint is a variable such that the implementation
|
||||||
|
// can be swapped out for unit tests.
|
||||||
|
var newSDKEndpoint = credentialsEndpoint
|
||||||
|
|
||||||
// newAWSLogsClient creates the service client for Amazon CloudWatch Logs.
|
// newAWSLogsClient creates the service client for Amazon CloudWatch Logs.
|
||||||
// Customizations to the default client from the SDK include a Docker-specific
|
// Customizations to the default client from the SDK include a Docker-specific
|
||||||
// User-Agent string and automatic region detection using the EC2 Instance
|
// User-Agent string and automatic region detection using the EC2 Instance
|
||||||
|
@ -222,11 +230,33 @@ func newAWSLogsClient(info logger.Info) (api, error) {
|
||||||
}
|
}
|
||||||
region = &r
|
region = &r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sess, err := session.NewSession()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Failed to create a service client session for for awslogs driver")
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach region to cloudwatchlogs config
|
||||||
|
sess.Config.Region = region
|
||||||
|
|
||||||
|
if uri, ok := info.Config[credentialsEndpointKey]; ok {
|
||||||
|
logrus.Debugf("Trying to get credentials from awslogs-credentials-endpoint")
|
||||||
|
|
||||||
|
endpoint := fmt.Sprintf("%s%s", newSDKEndpoint, uri)
|
||||||
|
creds := endpointcreds.NewCredentialsClient(*sess.Config, sess.Handlers, endpoint,
|
||||||
|
func(p *endpointcreds.Provider) {
|
||||||
|
p.ExpiryWindow = 5 * time.Minute
|
||||||
|
})
|
||||||
|
|
||||||
|
// attach credentials to cloudwatchlogs config
|
||||||
|
sess.Config.Credentials = creds
|
||||||
|
}
|
||||||
|
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"region": *region,
|
"region": *region,
|
||||||
}).Debug("Created awslogs client")
|
}).Debug("Created awslogs client")
|
||||||
|
|
||||||
client := cloudwatchlogs.New(session.New(), aws.NewConfig().WithRegion(*region))
|
client := cloudwatchlogs.New(sess)
|
||||||
|
|
||||||
client.Handlers.Build.PushBackNamed(request.NamedHandler{
|
client.Handlers.Build.PushBackNamed(request.NamedHandler{
|
||||||
Name: "DockerUserAgentHandler",
|
Name: "DockerUserAgentHandler",
|
||||||
|
@ -525,6 +555,7 @@ func ValidateLogOpt(cfg map[string]string) error {
|
||||||
case tagKey:
|
case tagKey:
|
||||||
case datetimeFormatKey:
|
case datetimeFormatKey:
|
||||||
case multilinePatternKey:
|
case multilinePatternKey:
|
||||||
|
case credentialsEndpointKey:
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown log opt '%s' for %s log driver", key, name)
|
return fmt.Errorf("unknown log opt '%s' for %s log driver", key, name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,10 @@ package awslogs
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -1065,3 +1068,121 @@ func BenchmarkUnwrapEvents(b *testing.B) {
|
||||||
as.Len(res, maximumLogEventsPerPut)
|
as.Len(res, maximumLogEventsPerPut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewAWSLogsClientCredentialEndpointDetect(t *testing.T) {
|
||||||
|
// required for the cloudwatchlogs client
|
||||||
|
os.Setenv("AWS_REGION", "us-west-2")
|
||||||
|
defer os.Unsetenv("AWS_REGION")
|
||||||
|
|
||||||
|
credsResp := `{
|
||||||
|
"AccessKeyId" : "test-access-key-id",
|
||||||
|
"SecretAccessKey": "test-secret-access-key"
|
||||||
|
}`
|
||||||
|
|
||||||
|
expectedAccessKeyID := "test-access-key-id"
|
||||||
|
expectedSecretAccessKey := "test-secret-access-key"
|
||||||
|
|
||||||
|
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
fmt.Fprintln(w, credsResp)
|
||||||
|
}))
|
||||||
|
defer testServer.Close()
|
||||||
|
|
||||||
|
// set the SDKEndpoint in the driver
|
||||||
|
newSDKEndpoint = testServer.URL
|
||||||
|
|
||||||
|
info := logger.Info{
|
||||||
|
Config: map[string]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
info.Config["awslogs-credentials-endpoint"] = "/creds"
|
||||||
|
|
||||||
|
c, err := newAWSLogsClient(info)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
client := c.(*cloudwatchlogs.CloudWatchLogs)
|
||||||
|
|
||||||
|
creds, err := client.Config.Credentials.Get()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expectedAccessKeyID, creds.AccessKeyID)
|
||||||
|
assert.Equal(t, expectedSecretAccessKey, creds.SecretAccessKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewAWSLogsClientCredentialEnvironmentVariable(t *testing.T) {
|
||||||
|
// required for the cloudwatchlogs client
|
||||||
|
os.Setenv("AWS_REGION", "us-west-2")
|
||||||
|
defer os.Unsetenv("AWS_REGION")
|
||||||
|
|
||||||
|
expectedAccessKeyID := "test-access-key-id"
|
||||||
|
expectedSecretAccessKey := "test-secret-access-key"
|
||||||
|
|
||||||
|
os.Setenv("AWS_ACCESS_KEY_ID", expectedAccessKeyID)
|
||||||
|
defer os.Unsetenv("AWS_ACCESS_KEY_ID")
|
||||||
|
|
||||||
|
os.Setenv("AWS_SECRET_ACCESS_KEY", expectedSecretAccessKey)
|
||||||
|
defer os.Unsetenv("AWS_SECRET_ACCESS_KEY")
|
||||||
|
|
||||||
|
info := logger.Info{
|
||||||
|
Config: map[string]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := newAWSLogsClient(info)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
client := c.(*cloudwatchlogs.CloudWatchLogs)
|
||||||
|
|
||||||
|
creds, err := client.Config.Credentials.Get()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expectedAccessKeyID, creds.AccessKeyID)
|
||||||
|
assert.Equal(t, expectedSecretAccessKey, creds.SecretAccessKey)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewAWSLogsClientCredentialSharedFile(t *testing.T) {
|
||||||
|
// required for the cloudwatchlogs client
|
||||||
|
os.Setenv("AWS_REGION", "us-west-2")
|
||||||
|
defer os.Unsetenv("AWS_REGION")
|
||||||
|
|
||||||
|
expectedAccessKeyID := "test-access-key-id"
|
||||||
|
expectedSecretAccessKey := "test-secret-access-key"
|
||||||
|
|
||||||
|
contentStr := `
|
||||||
|
[default]
|
||||||
|
aws_access_key_id = "test-access-key-id"
|
||||||
|
aws_secret_access_key = "test-secret-access-key"
|
||||||
|
`
|
||||||
|
content := []byte(contentStr)
|
||||||
|
|
||||||
|
tmpfile, err := ioutil.TempFile("", "example")
|
||||||
|
defer os.Remove(tmpfile.Name()) // clean up
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = tmpfile.Write(content)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = tmpfile.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
os.Unsetenv("AWS_ACCESS_KEY_ID")
|
||||||
|
os.Unsetenv("AWS_SECRET_ACCESS_KEY")
|
||||||
|
|
||||||
|
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", tmpfile.Name())
|
||||||
|
defer os.Unsetenv("AWS_SHARED_CREDENTIALS_FILE")
|
||||||
|
|
||||||
|
info := logger.Info{
|
||||||
|
Config: map[string]string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := newAWSLogsClient(info)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
client := c.(*cloudwatchlogs.CloudWatchLogs)
|
||||||
|
|
||||||
|
creds, err := client.Config.Credentials.Get()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, expectedAccessKeyID, creds.AccessKeyID)
|
||||||
|
assert.Equal(t, expectedSecretAccessKey, creds.SecretAccessKey)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue