localstack / localstack

💻 A fully functional local AWS cloud stack. Develop and test your cloud & Serverless apps offline
https://localstack.cloud
Other
56.27k stars 4.01k forks source link

No detection of bad policy in `sts.GetFederationToken` #10746

Open wunderbarb opened 6 months ago

wunderbarb commented 6 months ago

Is there an existing issue for this?

Current Behavior

localstack accepts policy with a defined Principal. This is not true for real AWS. Example: { "Version":"2012-10-17", "Statement":[ { "Sid":"AllowUploads", "Effect":"Allow", "Principal":{"AWS":"*"}, "Action":"s3:PutObject", "Resource":"arn:aws:s3:::%s/*" } ] }

Expected Behavior

There should be an error Policy document should not specify a principal.

How are you starting LocalStack?

With the localstack script

Steps To Reproduce

How are you starting localstack (e.g., bin/localstack command, arguments, or docker-compose.yml)

docker run localstack/localstack

Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)

awslocal s3 mb s3://mybucket

Environment

- OS: Ubuntu 20.4
- LocalStack: 3.2.1.dev20240307125457
Version Pro

Anything else?

No response

marcciosilva commented 3 months ago

@wunderbarb Thank you for reaching out to us. Can you please provide us with a brief sample explaining the steps one should take to reproduce the issue? E.g. the full set of aws/awslocal commands you're using. I'm interested in being able to reproduce this error against AWS.

wunderbarb commented 3 months ago

@marcciosilva find below an extract of GO code of my library that demonstrated the issue.

func getPrefixToken1(gft getPrefixTokenInput, opts ...Option) (Token, error) {

    clSTS := sts.NewFromConfig(cfg)
    gftOut, err := clSTS.GetFederationToken(context.Background(), &sts.GetFederationTokenInput{
        Name:            aws.String(gft.name),
        DurationSeconds: aws.Int32(int32(gft.expires.Seconds())),
        Policy:          getPolicy1(gft.path),
    })
    if err != nil {
        return Token{}, errors.WithMessage(err, "get federation token failed")
    }
    return Token{
        Name:         gft.name,
        AccessKeyID:  *gftOut.Credentials.AccessKeyId,
        SecretKey:    *gftOut.Credentials.SecretAccessKey,
        SessionToken: *gftOut.Credentials.SessionToken,
    }, nil
}

func getPolicy1(path string) *string {
    path = strings.TrimSuffix(strings.TrimPrefix(path, "s3://"), "/")
    s := fmt.Sprintf(`{
  "Version":"2012-10-17",
  "Statement":[
    {
        "Sid":"AllowUploads",
        "Effect":"Allow",
        "Principal":{ "AWS":"*"},
        "Action":"s3:PutObject",
        "Resource":"arn:aws:s3:::%s/*"
    },
    {
      "Sid":"AllowMultipartUploads",
      "Effect":"Allow",
      "Action":"s3:CreateMultipartUpload",
      "Resource":"arn:aws:s3:::%s/*"
    }
  ]
}`, path, path)
    return aws.String(s)
}

The code uses aws-sdk-go-v2. When testing using localstack pro, the Token is generated without an error. When testing on real S3 (using a real account), AWS triggers the error. Of course, when removing the line with "Principal" from the policy statement in getPolicy1, AWS is happy and generates a valid token.