update dependencies (#6267)
Signed-off-by: hongming <coder.scala@gmail.com>
This commit is contained in:
243
vendor/github.com/open-policy-agent/opa/plugins/rest/aws.go
generated
vendored
243
vendor/github.com/open-policy-agent/opa/plugins/rest/aws.go
generated
vendored
@@ -30,8 +30,11 @@ const (
|
||||
ec2DefaultTokenPath = "http://169.254.169.254/latest/api/token"
|
||||
|
||||
// ref. https://docs.aws.amazon.com/AmazonECS/latest/userguide/task-iam-roles.html
|
||||
ecsDefaultCredServicePath = "http://169.254.170.2"
|
||||
ecsRelativePathEnvVar = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
|
||||
ecsDefaultCredServicePath = "http://169.254.170.2"
|
||||
ecsRelativePathEnvVar = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
|
||||
ecsFullPathEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI"
|
||||
ecsAuthorizationTokenEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN"
|
||||
ecsAuthorizationTokenFileEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE"
|
||||
|
||||
// ref. https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html
|
||||
stsDefaultDomain = "amazonaws.com"
|
||||
@@ -211,7 +214,12 @@ func (cs *awsMetadataCredentialService) urlForMetadataService() (string, error)
|
||||
// otherwise, check environment to see if it looks like we're in an ECS
|
||||
// container (with implied role association)
|
||||
if isECS() {
|
||||
return ecsDefaultCredServicePath + os.Getenv(ecsRelativePathEnvVar), nil
|
||||
// first check if the relative env var exists; if so we use that otherwise we
|
||||
// use the "full" var
|
||||
if _, relativeExists := os.LookupEnv(ecsRelativePathEnvVar); relativeExists {
|
||||
return ecsDefaultCredServicePath + os.Getenv(ecsRelativePathEnvVar), nil
|
||||
}
|
||||
return os.Getenv(ecsFullPathEnvVar), nil
|
||||
}
|
||||
// if there's no role name and we don't appear to have a path to the
|
||||
// ECS container service, then the configuration is invalid
|
||||
@@ -267,6 +275,29 @@ func (cs *awsMetadataCredentialService) refreshFromService(ctx context.Context)
|
||||
return errors.New("unable to construct metadata HTTP request: " + err.Error())
|
||||
}
|
||||
|
||||
// if using the AWS_CONTAINER_CREDENTIALS_FULL_URI variable, we need to associate the token
|
||||
// to the request
|
||||
if _, useFullPath := os.LookupEnv(ecsFullPathEnvVar); useFullPath {
|
||||
var token string
|
||||
tokenFilePath, tokenFilePathExists := os.LookupEnv(ecsAuthorizationTokenFileEnvVar)
|
||||
|
||||
if tokenFilePathExists {
|
||||
tokenBytes, err := os.ReadFile(tokenFilePath)
|
||||
if err != nil {
|
||||
return errors.New("failed to read ECS metadata authorization token from file: " + err.Error())
|
||||
}
|
||||
token = string(tokenBytes)
|
||||
// If token doesn't exist as a file check if it exists as an environment variable
|
||||
} else {
|
||||
var tokenExists bool
|
||||
token, tokenExists = os.LookupEnv(ecsAuthorizationTokenEnvVar)
|
||||
if !tokenExists {
|
||||
return errors.New("unable to get ECS metadata authorization token")
|
||||
}
|
||||
}
|
||||
req.Header.Set("Authorization", token)
|
||||
}
|
||||
|
||||
// if in the EC2 environment, we will use IMDSv2, which requires a session cookie from a
|
||||
// PUT request on the token endpoint before it will give the credentials, this provides
|
||||
// protection from SSRF attacks
|
||||
@@ -318,6 +349,169 @@ func (cs *awsMetadataCredentialService) credentials(ctx context.Context) (aws.Cr
|
||||
return cs.creds, nil
|
||||
}
|
||||
|
||||
// awsAssumeRoleCredentialService represents a STS credential service that uses active IAM credentials
|
||||
// to obtain temporary security credentials generated by AWS STS via AssumeRole API operation
|
||||
type awsAssumeRoleCredentialService struct {
|
||||
RegionName string `json:"aws_region"`
|
||||
RoleArn string `json:"iam_role_arn"`
|
||||
SessionName string `json:"session_name"`
|
||||
Domain string `json:"aws_domain"`
|
||||
AWSSigningPlugin *awsSigningAuthPlugin `json:"aws_signing,omitempty"`
|
||||
stsURL string
|
||||
creds aws.Credentials
|
||||
expiration time.Time
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
func (cs *awsAssumeRoleCredentialService) populateFromEnv() error {
|
||||
if cs.AWSSigningPlugin == nil {
|
||||
return errors.New("a AWS signing plugin must be specified when AssumeRole credential provider is enabled")
|
||||
}
|
||||
|
||||
switch {
|
||||
case cs.AWSSigningPlugin.AWSEnvironmentCredentials != nil:
|
||||
case cs.AWSSigningPlugin.AWSProfileCredentials != nil:
|
||||
case cs.AWSSigningPlugin.AWSMetadataCredentials != nil:
|
||||
default:
|
||||
return errors.New("unsupported AWS signing plugin with AssumeRole credential provider")
|
||||
}
|
||||
|
||||
if cs.AWSSigningPlugin.AWSMetadataCredentials != nil {
|
||||
if cs.AWSSigningPlugin.AWSMetadataCredentials.RegionName == "" {
|
||||
if cs.AWSSigningPlugin.AWSMetadataCredentials.RegionName = os.Getenv(awsRegionEnvVar); cs.AWSSigningPlugin.AWSMetadataCredentials.RegionName == "" {
|
||||
return errors.New("no " + awsRegionEnvVar + " set in environment or configuration")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cs.AWSSigningPlugin.AWSSignatureVersion == "" {
|
||||
cs.AWSSigningPlugin.AWSSignatureVersion = "4"
|
||||
}
|
||||
|
||||
if cs.Domain == "" {
|
||||
cs.Domain = os.Getenv(awsDomainEnvVar)
|
||||
}
|
||||
|
||||
if cs.RegionName == "" {
|
||||
if cs.RegionName = os.Getenv(awsRegionEnvVar); cs.RegionName == "" {
|
||||
return errors.New("no " + awsRegionEnvVar + " set in environment or configuration")
|
||||
}
|
||||
}
|
||||
|
||||
if cs.RoleArn == "" {
|
||||
if cs.RoleArn = os.Getenv(awsRoleArnEnvVar); cs.RoleArn == "" {
|
||||
return errors.New("no " + awsRoleArnEnvVar + " set in environment or configuration")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *awsAssumeRoleCredentialService) signingCredentials(ctx context.Context) (aws.Credentials, error) {
|
||||
if cs.AWSSigningPlugin.AWSEnvironmentCredentials != nil {
|
||||
cs.AWSSigningPlugin.AWSEnvironmentCredentials.logger = cs.logger
|
||||
return cs.AWSSigningPlugin.AWSEnvironmentCredentials.credentials(ctx)
|
||||
}
|
||||
|
||||
if cs.AWSSigningPlugin.AWSProfileCredentials != nil {
|
||||
cs.AWSSigningPlugin.AWSProfileCredentials.logger = cs.logger
|
||||
return cs.AWSSigningPlugin.AWSProfileCredentials.credentials(ctx)
|
||||
}
|
||||
|
||||
cs.AWSSigningPlugin.AWSMetadataCredentials.logger = cs.logger
|
||||
return cs.AWSSigningPlugin.AWSMetadataCredentials.credentials(ctx)
|
||||
}
|
||||
|
||||
func (cs *awsAssumeRoleCredentialService) stsPath() string {
|
||||
return getSTSPath(cs.Domain, cs.stsURL, cs.RegionName)
|
||||
}
|
||||
|
||||
func (cs *awsAssumeRoleCredentialService) refreshFromService(ctx context.Context) error {
|
||||
// define the expected JSON payload from the EC2 credential service
|
||||
// ref. https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
|
||||
type responsePayload struct {
|
||||
Result struct {
|
||||
Credentials struct {
|
||||
SessionToken string
|
||||
SecretAccessKey string
|
||||
Expiration time.Time
|
||||
AccessKeyID string `xml:"AccessKeyId"`
|
||||
}
|
||||
} `xml:"AssumeRoleResult"`
|
||||
}
|
||||
|
||||
// short circuit if a reasonable amount of time until credential expiration remains
|
||||
if time.Now().Add(time.Minute * 5).Before(cs.expiration) {
|
||||
cs.logger.Debug("Credentials previously obtained from sts service still valid.")
|
||||
return nil
|
||||
}
|
||||
|
||||
cs.logger.Debug("Obtaining credentials from sts for role %s.", cs.RoleArn)
|
||||
|
||||
var sessionName string
|
||||
if cs.SessionName == "" {
|
||||
sessionName = "open-policy-agent"
|
||||
} else {
|
||||
sessionName = cs.SessionName
|
||||
}
|
||||
|
||||
queryVals := url.Values{
|
||||
"Action": []string{"AssumeRole"},
|
||||
"RoleSessionName": []string{sessionName},
|
||||
"RoleArn": []string{cs.RoleArn},
|
||||
"Version": []string{"2011-06-15"},
|
||||
}
|
||||
stsRequestURL, _ := url.Parse(cs.stsPath())
|
||||
|
||||
// construct an HTTP client with a reasonably short timeout
|
||||
client := &http.Client{Timeout: time.Second * 10}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, stsRequestURL.String(), strings.NewReader(queryVals.Encode()))
|
||||
if err != nil {
|
||||
return errors.New("unable to construct STS HTTP request: " + err.Error())
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
// Note: Calls to AWS STS AssumeRole must be signed using the access key ID
|
||||
// and secret access key
|
||||
signingCreds, err := cs.signingCredentials(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = aws.SignRequest(req, "sts", signingCreds, time.Now(), cs.AWSSigningPlugin.AWSSignatureVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
body, err := aws.DoRequestWithClient(req, client, "STS", cs.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var payload responsePayload
|
||||
err = xml.Unmarshal(body, &payload)
|
||||
if err != nil {
|
||||
return errors.New("failed to parse credential response from STS service: " + err.Error())
|
||||
}
|
||||
|
||||
cs.expiration = payload.Result.Credentials.Expiration
|
||||
cs.creds.AccessKey = payload.Result.Credentials.AccessKeyID
|
||||
cs.creds.SecretKey = payload.Result.Credentials.SecretAccessKey
|
||||
cs.creds.SessionToken = payload.Result.Credentials.SessionToken
|
||||
cs.creds.RegionName = cs.RegionName
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *awsAssumeRoleCredentialService) credentials(ctx context.Context) (aws.Credentials, error) {
|
||||
err := cs.refreshFromService(ctx)
|
||||
if err != nil {
|
||||
return cs.creds, err
|
||||
}
|
||||
return cs.creds, nil
|
||||
}
|
||||
|
||||
// awsWebIdentityCredentialService represents an STS WebIdentity credential services
|
||||
type awsWebIdentityCredentialService struct {
|
||||
RoleArn string
|
||||
@@ -354,23 +548,7 @@ func (cs *awsWebIdentityCredentialService) populateFromEnv() error {
|
||||
}
|
||||
|
||||
func (cs *awsWebIdentityCredentialService) stsPath() string {
|
||||
var domain string
|
||||
if cs.Domain != "" {
|
||||
domain = strings.ToLower(cs.Domain)
|
||||
} else {
|
||||
domain = stsDefaultDomain
|
||||
}
|
||||
|
||||
var stsPath string
|
||||
switch {
|
||||
case cs.stsURL != "":
|
||||
stsPath = cs.stsURL
|
||||
case cs.RegionName != "":
|
||||
stsPath = fmt.Sprintf(stsRegionPath, strings.ToLower(cs.RegionName), domain)
|
||||
default:
|
||||
stsPath = fmt.Sprintf(stsDefaultPath, domain)
|
||||
}
|
||||
return stsPath
|
||||
return getSTSPath(cs.Domain, cs.stsURL, cs.RegionName)
|
||||
}
|
||||
|
||||
func (cs *awsWebIdentityCredentialService) refreshFromService(ctx context.Context) error {
|
||||
@@ -457,8 +635,9 @@ func (cs *awsWebIdentityCredentialService) credentials(ctx context.Context) (aws
|
||||
|
||||
func isECS() bool {
|
||||
// the special relative path URI is set by the container agent in the ECS environment only
|
||||
_, isECS := os.LookupEnv(ecsRelativePathEnvVar)
|
||||
return isECS
|
||||
_, isECSRelative := os.LookupEnv(ecsRelativePathEnvVar)
|
||||
_, isECSFull := os.LookupEnv(ecsFullPathEnvVar)
|
||||
return isECSRelative || isECSFull
|
||||
}
|
||||
|
||||
// ecrAuthPlugin authorizes requests to AWS ECR.
|
||||
@@ -555,3 +734,23 @@ func (ap *awsKMSSignPlugin) SignDigest(ctx context.Context, digest []byte, keyID
|
||||
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
func getSTSPath(stsDomain, stsURL, regionName string) string {
|
||||
var domain string
|
||||
if stsDomain != "" {
|
||||
domain = strings.ToLower(stsDomain)
|
||||
} else {
|
||||
domain = stsDefaultDomain
|
||||
}
|
||||
|
||||
var stsPath string
|
||||
switch {
|
||||
case stsURL != "":
|
||||
stsPath = stsURL
|
||||
case regionName != "":
|
||||
stsPath = fmt.Sprintf(stsRegionPath, strings.ToLower(regionName), domain)
|
||||
default:
|
||||
stsPath = fmt.Sprintf(stsDefaultPath, domain)
|
||||
}
|
||||
return stsPath
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user