简体   繁体   中英

get HTTP/1.1 403 Forbidden when trying to access private content stored in S3(static web hosting) using cloudfront and privateKey

I am receiving following response from AWS CloudFront from Java application where I am trying to access a private content (web page) using signed cookies.

HTTP/1.1 403 Forbidden [Content-Type: application/xml, Transfer-Encoding: chunked, Connection: keep-alive, Date: Fri, 23 Aug 2019 12:47:53 GMT, Server: AmazonS3, X-Cache: Error from cloudfront, Via: 1.1 1b964435***********d975cdd***.cloudfront.net (CloudFront), X-Amz-Cf-Pop: MXP64-C1, X-Amz-Cf-Id: 6Waw****_ukbfaev1nrJZZYBl**********t66R9ctZ*****A==] org.apache.http.conn.BasicManagedEntity@5fdba6f9

I tried the following steps:

  1. I have configured an S3 bucked as "Static website hosting"
  2. set the bucket policy as :
{
    "Version": "2012-10-17",
    "Statement": [
          {
            "Sid": "2",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E1J***SIQ****"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::my-xxxxx-s3-bucket/*"
        }
    ]
}
  1. CORS configuration of the bucket as :
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>
  1. create a CloudFront distribution with:

    • Origin Settings -> Origin Domain Name: my-s3-bucket-name
    • Origin Settings -> Restrict Bucket Access: yes
    • Restrict Viewer Access(Use Signed URLs or Signed Cookies): yes.
    • Trusted Signers: self(checked).
    • leave rest of the properties default.
  2. Created security credential under (CloudFront key pairs) and downloaded the private key. convert the .pem file into .der using the following command.

openssl pkcs8 -topk8 -nocrypt -in origin.pem -inform PEM -out new.der -outform DER 
  1. created a Maven project with the following dependencies:
<dependencies>
  <dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk</artifactId>
    <version>1.11.327</version>
  </dependency>

    <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.62</version>
</dependency>

<!-- https://mvnrepository.com/artifact/net.java.dev.jets3t/jets3t -->
<dependency>
    <groupId>net.java.dev.jets3t</groupId>
    <artifactId>jets3t</artifactId>
    <version>0.9.4</version>
</dependency>
  1. the code is as below trying to access "index.html" file (saved in S3 the root directory) using signed cookies:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.spec.InvalidKeySpecException;
import java.text.ParseException;
import java.util.Date;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jets3t.service.CloudFrontServiceException;

import com.amazonaws.services.cloudfront.CloudFrontCookieSigner;
import com.amazonaws.services.cloudfront.CloudFrontCookieSigner.CookiesForCustomPolicy;
import com.amazonaws.services.cloudfront.util.SignerUtils;
import com.amazonaws.services.cloudfront.util.SignerUtils.Protocol;
import com.amazonaws.util.DateUtils;

public class SignedCookies {

    public static void withCustom() throws InvalidKeySpecException, IOException{

        Protocol protocol = Protocol.http;
        String resourcePath = "index.html";
        String distributionDomain = "***ju***lu***.cloudfront.net";
        String privateKeyFilePath = "my-path/pk-APKA####K3WH####7U##.der";
        File privateKeyFile = new File(privateKeyFilePath);
        String s3ObjectKey = "index.html";
        String keyPairId = "APKA####K3WH####7U##";


         Date activeFrom = DateUtils.parseISO8601Date("2018-11-14T22:20:00.000Z");
         Date expiresOn = DateUtils.parseISO8601Date("2020-11-14T22:20:00.000Z");
         String ipRange = null;

         CookiesForCustomPolicy cookies = CloudFrontCookieSigner.getCookiesForCustomPolicy(
                      protocol, distributionDomain, privateKeyFile, s3ObjectKey,
                      keyPairId, expiresOn, activeFrom, ipRange);


         @SuppressWarnings({ "resource", "deprecation" })
        HttpClient client = new DefaultHttpClient();
         HttpGet httpGet = new HttpGet(
                      SignerUtils.generateResourcePath(protocol, distributionDomain,
                      resourcePath));

         httpGet.addHeader("Cookie", "Secure");
         httpGet.addHeader("Cookie", cookies.getPolicy().getKey() + "=" +
             cookies.getPolicy().getValue());
         httpGet.addHeader("Cookie", cookies.getSignature().getKey() + "=" +
             cookies.getSignature().getValue());
         httpGet.addHeader("Cookie", cookies.getKeyPairId().getKey() + "=" +
             cookies.getKeyPairId().getValue());


         HttpResponse response = client.execute(httpGet);

         System.out.println(response.toString());

    }

    public static void main(String[] args) throws FileNotFoundException, IOException, CloudFrontServiceException, ParseException, InvalidKeySpecException {
        withCustom();
    }

}

  1. And I have received 403 response.

How can I fix this issue?

please first read my last comment under my first post. this part is related to the previous post. here is the code sample I used to sign the URL with signUrlCanned and get the content but when I tried to use buildPolicyForSignedUrl got access denied error.

@JamesDean: thanks for your comments. In the above example. I choose Origin Domain Name from the drop-down (as s3 bucket) and used OAI where I used S3 was configured as a static website, which was my first mistake. Anyway, I resolved this by providing a custom origin name (static website endpoint URL). Then tested without enabling "Use Signed URLs or Signed Cookies", and worked without any issue. but if I enable "Use Signed URLs or Signed Cookies" and tried to use Signed URL or Signed cookies got the 403 error which I could not solve yet. I am providing the code sample below if you can help me anyway.

using following code I get the correct signed url and can access the content:

byte[] derPrivateKey = EncryptionUtil.convertRsaPemToDer(new FileInputStream(privateKeyFilePath));
//      Generate a "canned" signed URL to allow access to a specific distribution and object

        String signedUrlCanned = CloudFrontService.signUrlCanned(
            "https://" + distributionDomain + "/" + s3ObjectKey, // Resource URL or Path
            keyPairId,     // Certificate identifier, an active trusted signer for the distribution
            derPrivateKey, // DER Private key data
            ServiceUtils.parseIso8601Date("2020-08-30T22:20:00.000Z") // DateLessThan
            );
        System.out.println(signedUrlCanned);

On the other hand, when I tried to access the content using a custom policy for the same s3 content (index.html in the root) I got access denied:

String policyResourcePath = distributionDomain + "/*" ;
//      Convert an RSA PEM private key file to DER bytes

        byte[] derPrivateKey = EncryptionUtil.convertRsaPemToDer(new FileInputStream(privateKeyFilePath));

        String policy = CloudFrontService.buildPolicyForSignedUrl(
                policyResourcePath, // Resource path (optional, may include '*' and '?' wildcards)
                ServiceUtils.parseIso8601Date("2020-11-14T22:20:00.000Z"), // DateLessThan
                "0.0.0.0/0", // CIDR IP address restriction (optional, 0.0.0.0/0 means everyone)
                ServiceUtils.parseIso8601Date("2017-10-16T06:31:56.000Z")  // DateGreaterThan (optional)
                );

        String signedUrl = CloudFrontService.signUrl(
                "https://" + distributionDomain + "/" + s3ObjectKey, // Resource URL or Path
                keyPairId,     // Certificate identifier, an active trusted signer for the distribution
                derPrivateKey, // DER Private key data
                policy // Access control policy
                );
            System.out.println(signedUrl);

The response I received:


<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>AccessDenied</Code>
    <Message>Access denied</Message>
</Error>

Code reference: https://jets3t.s3.amazonaws.com/toolkit/code-samples.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM