As asked in the title, is it by default the communication between AWS services uses SSL? For example, a Lambda function writes Objects to S3, or a Lambda function reads data from Kinesis.
You can check AWS's Services and their supported protocols in the docs.
The SDK will always opt for HTTPS traffic unless specified otherwise. You can specify so by changing the endpoint attribute for the service you are working with. Just check the link above to fetch the right endpoint for the service you are looking for.
You can see how to do so in the official docs for the SDK, like so:
const s3 = new AWS.S3({endpoint: 'https://s3.us-east-1.amazonaws.com'});
Here's a link for S3's Javascript SDK:
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property
You also have the option to enable/disable SSL by setting the sslEnabled attribute to either true or false. Even though the docs don't state anything for its default value, I truly believe this flag is set to true automatically. Setting this flag will only take effect if the protocol has not been previously specified in the endpoint attribute.
And this is extracted from the Java SDK:
Callers can pass in just the endpoint (ex: "ec2.amazonaws.com") or a
full URL, including the protocol (ex: "https://ec2.amazonaws.com"). If
the protocol is not specified here, the default protocol from this
client's ClientConfiguration will be used, which by default is HTTPS.
I have found a thread in AWS's forums which states that SSL is always enabled for SDK's requests:
If you specify AWS.config.sslEnabled = true, all endpoints will use
SSL by default. There is no "fallback" to HTTP if HTTPS doesn't work
or anything like that.
This can be overridden when creating an endpoint, for example by new
AWS.S3({sslEnabled: false}) - that is why it is only a default
setting. If you do not explicitly say sslEnabled: false in your code,
you can be assured that SSL is used everywhere. And finally, even when
specifying sslEnabled: true, if creating a new endpoint explicitly
with a full URL, such as http://s3-eu-west-1.amazonaws.com, will
override the sslEnabled setting. To say it in another way, sslEnabled
only affects if http:// or https:// is automatically added to hosts
specified without specifying a protocol.
And the default is to use SSL for all Amazon services by default, so
adding a bucket policy that will limit connections to using SSL only
will only block explicit attempts to access S3 without HTTPS (or users
of different SDK:s or other access methods).
Hope this helps.
Related
AWS have recently released the Lambda function URLs feature which allows a function to be invoked via a URL.
I would like to allow my function to be invoked via a URL but only via CloudFront.
I don't want people to be able to bypass CloudFront and invoke the function directly.
Is there a way to configure this? I am aware that I can restrict the function URL by setting the auth type to AWS_IAM but am not clear on how I then allow CloudFront to call it.
Currently, the only option I see is quite similar to how you would protect an ALB in a way that access is restricted to CloudFront:
Configure CloudFront to add a custom HTTP header to requests that it sends to the Application Load Balancer lambda function URL.
Configure the Application Load Balancer Lambda to only forward process requests that contain the custom HTTP header.
My thoughts on approaches that may not work when using lambda function URLs:
IAM auth (since I see no way to sign these requests origination from CloudFront, maybe that will change in the future when lambda function URLs become a first class citizen like S3-origins)
restricting access via security groups (because there are no SGs for lambda func URLs)
Confirmed with AWS support that there is currently no way to do this: "[with the] current design of CloudFront, it is not possible for CloudFront to relay IAM authenticated requests to Lambda URL origin.." There is a feature request for this (but they did not provide a timeframe for implementation and release) but hopefully they provide a solution similar to, and as straight forward as, the CloudFront integration with S3 via the Origin Access Identity.
Here's what I did to make it work on my side :
go to the CloudFront page
click on create a new distribution
In section Origin domain you have to paste in your lambda function URL
Make sure to adjust the caching policy depending on what your lambda function consumes
You might want to create a dedicated policy in you want the cache key to depend on the query string, the cookies, etc...
For my use case I created a new policy to take into account the query string
I have a custom domain set up in AWS API Gateway. My intention is to use "API mappings" to send traffic for different API versions to their respective API Gateways, e.g.:
GET https://example.com/v1/foo is sent to an API gateway "APIv1" ($default stage) via an API mapping on the custom domain with path="v1".
GET https://example.com/v2/foo is sent to an API gateway "APIv2" ($default stage) via an API mapping on the custom domain with path="v2" (not shown)
The HTTP APIs themselves are configured with a single route /{proxy+} and an integration that sends requests to a private ALB:
This setup works fine as far as routing traffic goes, but the problem is that when the request makes it to the actual application, the routes the application receives are like /v1/foo instead of just /foo, which is what the app is expecting.
I've played around with different route matching and parameter mapping (of which I can find almost no examples for my use case) to no avail.
I could change my app code to match the routes that AWS is sending, but the entire point of this was to handle versioning using my AWS stack and not app code. Do I have another option?
If you create a resource called /foo and the proxy resource inside it, when you set integration you can define which path to pass and the {proxy} will have just the part after /foo, ignoring the v1 entirely.
See an example below.
In this case it is ignoring everything before v1 and it is also rewriting the integration to /api/{proxy}.
It will receive a request as GET https://example.com/abc/xyz/v1/foo and will forward to backend as GET https://example.com/api/foo.
Update
It can't be done via VPC Link, but we can use public ALB almost like private, like the explanation below.
It explain about CloudFront, but the same is valid for API Gateway.
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/restrict-access-to-load-balancer.html
It's totally possible. You just need to use parameters mapping for this. Using the AWS UI it would be:
I am new to Lambda so I would like to understand how the following scenario can be deployed:
Lambda connected to API gateway ( which in turn connected to a reverse proxy)
The request from API gateway to lambda needs to be routed to 3 different ALBs each in different (VPCs) private subnets.
What configuration changes I need to bring in to achieve this apart from writing Lambda function (using python) to rewrite the urls?
It would be nice if someone can explain the message flow here.
Thanks
Abhijit
This to me seems to be multiple issues, I'll try to break down whats trying to be achieved.
Using ALBs with API Gateway
There are many options for how API Gateway can use load balancers to serve http traffic. The solution really depends on which type of API Gateway you are trying to use.
Assuming your API is either REST or WebSockets you are left with 2 choices for enabling HTTP traffic inbound to a load balancer:
Directly as a HTTP or HTTP_PROXY request, listing publicly accessible hostnames to which API Gateway will forward the traffic.
If you want to keep transit private then your only option is to create a network load balancer and make use of VPCLink to create a private connection between API Gateway and your Network resource.
If you're creating a HTTP API (sometimes referred to as API Gateway v2) then you can make use of direct connection to a private ALB, however be aware that at this time HTTP API does not support all the features of REST APIs so you would want to compare feature sets before doing this.
Using multiple load balancers to direct traffic
You determine the value per each resource/method combo, for example POST /example would be assigned its target endpoint, but only one.
My suggestion would be to make use of stage variables if you're using a REST API to specify any endpoints that you're forwarding traffic for the following reasons:
Prevents mistyping of domain names
Allows quick replacement of a hostname
Provides functionality for canary deployments to shift traffic proportionally between 2 variable names (these could be anything as long as the type is the same e.g. Lambda to another Lambda, not Lambda to a load balancer).
Using a Lambda to redirect
Technically a Lambda can perform a redirect by return a response using the below syntax
{
statusCode: 302,
headers: {
Location: 'https://api.example.com/new/path',
}
}
However be aware this will change the request to become a GET request, this will also remove the payload of the body request when the redirect occurs. Additionally you would need to set this up for every resource/method combo that you wanted to redirect.
There are 2 options that you have available to get around these issues, both involve using CloudFront combined with a Lambda#Edge function.
The first solution can act as a workaround for the request type changing, in the Origin Request event you could modify the Request URI property to match the new URI structure. By doing this your clients would be able to use the API still, whilst you would notify them of the depercations to certain paths that you were migrating.
The second solution acts as a workaround for the need to add redirects to each resource/method combo which can create a lot of mess of methods just for redirects. You could create a Lambda#Edge function to perform the same redirect on an Origin Response event. You could create mappings in your Lambda function to work out which URL it should redirect to.
There are many great examples on the Lambda#Edge example functions page
When we upload data to S3, is it protected in transit by default (via HTTPS maybe)?
I found this article which, if I understand correctly, states S3 does not use HTTPS:
Amazon Simple Storage Service: You can still use HTTP with Amazon S3
and securely make authenticated requests. The service uses a different
secure signing protocol.
Should we in this case protect the data in transit with Client-Side Encryption?
The article you cited is obsolete. It was originally written in 2008, and apparently when updated in 2015, some of the outdated information was left in place.
The version refers to the particular algorithm for signing the request. These AWS services have deprecated the older, less-secure methods (signature versions 0 and 1) and will no longer allow them after September 2009.
Indeed, versions 0 and 1 are not supported.
A few AWS services don't support signature version 2:
Amazon Simple Storage Service: You can still use HTTP with Amazon S3 and securely make authenticated requests. The service uses a different secure signing protocol.
This is also inaccurate. S3 supports signature version 2 in all regions where signature version 2 was deployed. Regions launched in 2014 or later do not support V2 at all, they require Signature Version 4, and in those regions, S3 also requires Signature Version 4.
Importantly, though, none of this has anything at all to do with HTTPS.
From the same document:
Most AWS services accept HTTPS requests, including:
...
Amazon Simple Storage Service
Okay, so, let's revisit this line:
The service uses a different secure signing protocol.
This statement is not about encryption, or security of the payload. This is a statement about the secuity of the request authentication and authorization process -- its resistance to forgery and reverse-engineering -- whether or not the request is sent encrypted.
HTTPS is supported by S3, to protect data in transit.
Quoting from the Security section of the S3 FAQs:
You can securely upload/download your data to Amazon S3 via SSL
endpoints using the HTTPS protocol.
If you're using the https:// endpoint for S3, then your data in transit should be encrypted properly. The quote that you referred to in the question means that it's also possible to access S3 using http:// protocol, in which case the data wouldn't be encrypted in transit. See this related question.
If you were asking specifically about whether AWS CLI encrypts data in transit, then the answer is yes. See this question.
Also, please note that the primary purpose of using client-side encryption would be to encrypt data at rest, and to use an encryption algorithm of your own choosing. If you use client-side encryption but still use the http:// endpoint, your communication over the wire would still be unencrypted, technically speaking, because the cyphertexts being passed over the wire could be extracted by an attacker for analysis.
Update:
If you were asking specifically about AWS Java SDK, the default protocol is again https. Quoting from javadocs for AWS Java SDK:
By default, all service endpoints in all regions use the https
protocol. To use http instead, specify it in the ClientConfiguration
supplied at construction.
And from the javadocs for ClientConfiguration.getProtocol:
The default configuration is to use HTTPS for all requests for
increased security.
Client-side/server-side encryption's primary purpose is to secure data at rest. If anyone was to break open your cloud provider's data center somehow and steal the disks that had your data, you're making it difficult for them to get hold of your data in plaintext by encrypting it either client-side/server-side. Doing it client-side gives you the benefit of having more control on the encryption algorithm with the seemingly additional side-effect of your data not being transmitted in plaintext over the wire. However, the communication channel itself is not encrypted. If you were using a weak encryption algorithm for example, an attacker could still sniff the encrypted data over the wire and decrypt it. Also, it's important to know that using SSL means:
You as the client can be sure you're talking to AWS
Your communication with AWS is encrypted, so others can't intercept it
You have verification that the message received is the same as the
message sent
In essence, you definitely want to use SSL irrespective of whether you want to use client-side encryption or not.
I am integrating a web-relay into AWS-service which makes call-outs to a predefined path (
/some-fixed-path and it can not be configured) and I want to intercept it using a lambda on dedicated sub-domain, to keep this separated from the rest of our service, so I want the call-out to be http://subdomain.example.com/some-fixed-path.
I have a domain (lets call it example.com) registered and I have a hosted-zone defined. How can i create a record-set in the hosted-zone and use it in the API-gateway definition? (The url must not contain the stage...)
In the API-gateway definition, there is a "Custom domain name" option, but I can't figure out how to point to a record from my hosted-zone.
You should simply be able to follow the instructions for using a custom domain and then adding an alias record in your hosted zone to the CloudFront distribution provided by the API Gateway console.
You'll want to configure your custom domain with the base path pointing to your deployed stage. At that point you can than create your resource at some-fixed-path.
Note: API Gateway currently requires all APIs to be HTTPS, so if your call out can't be changed to support HTTPS, API Gateway will not work for this use case.
AWS has a detailed guide about how to do that exactly.
A few more things to pay attention to are:
Make sure you remember to re-deploy when you make any change to the API.
When you set up Base Path Mapping, make sure double check the API resource path and method. (For example, if you create the API gateway through lambda template, the API resource will be created under /{API name} instead of /).
A lot of people see Missing Authentication Token when they use API gateway for the first time due to those reasons.