I have an Fargate service setup with an ALB in front of it. I enabled application based sticky cookies, in order to maintain websocket connections between my server and the client. The names of the cookies the ALB sets are as follows: AWSALBAPP-0, AWSALBAPP-1 etc. Is there a way to change this and make the names appear as random strings?
I used aws cdk to provision the resources, and enabled cookie stickiness from the target group of the ApplicationLoadBalancedFargateService construct
Since you mentioned you used ApplicationLoadBalancedFargateService construct
In the Cdk docs ( ApplicationLoadBalancedFargateService construct) this construct has a property of Targetgroup
Using ApplicationTargetGroup construct, you can define cookie name
It would be something like this
const tg2 = new elbv2.ApplicationTargetGroup(this, 'TG2', {
targetType: elbv2.TargetType.INSTANCE,
port: 80,
stickinessCookieDuration: Duration.minutes(5),
stickinessCookieName: 'MyDeliciousCookie',
vpc,
});
Note: Names that start with the following prefixes are not allowed: AWSALB, AWSALBAPP, and AWSALBTG; they're reserved for use by the load balancer.Also , stickinessCookieName parameter depends on the presence of stickinessCookieDuration parameter. If stickinessCookieDuration is not set, stickinessCookieName will be omitted
Related
Background: We have an VPC, it has an Internet Gateway attached.
I would like to get the InternetGatewayId of the VPC via aws-cdk
vpc := awsec2.Vpc_FromLookup(stack, jsii.String(viper.GetString(`vpc.id`)), &awsec2.VpcLookupOptions{
VpcId: jsii.String(viper.GetString(`vpc.id`)),
}) //Here it returns awsec2.Ivpc
But according to the code, only awsec2.Vpc has a method InternetGatewayId(). How could I convert awsec2.Ivpc to awsec2.Vpc?
The Ivpc type returned from Vpc_FromLookup is a CDK convenience method to cache a limited set of VPC attributes at synth-time. Unfortunately, the Internet Gateway ID isn't one of them:
Currently you're unable to get the [Internet Gateway] ID for imported VPCs. To do that you'd have to specifically look up the Internet Gateway by name, which would require knowing the name beforehand.
A simple, deterministic workaround is to manually store the ID as a SSM Parameter Store Parameter. At synth-time, StringParameter_ValueFromLookup looks up and caches the IGW ID value as Context in cdk.context.json.:
igwID := awsssm.StringParameter_ValueFromLookup(stack, jsii.String("/my-params/vpc/igw-id"))
A more advanced CDK-only solution is to lookup the ID in a deploy-time CustomResource, which "can do arbitrary lookups or modifications during a CloudFormation deployment" (typically by making SDK calls using a Lambda). Note that this is not necessarily a better solution, because it introduces non-determinacy into the deployment.
I am having trouble understanding the point of AWS implementation of service discovery in ECS when using bridge mode, and in general a path forward to (relatively basic) container networking, despite the numerous AWS blog posts on the subject.
Service discovery seems to me about solving dynamically generated containers accessibility (in tasks), so that, similar to docker user defined networks, I can access different tasks on a cluster with a predefined canonical host name.name-space, in a VPC.
I've made sure in the VPC that:
DNS hostnames: Enabled
DNS resolution: Enabled
When service discovery is defined when using bridge mode:
it still tacks on a dynamic portion to the name i did not specify.
{
"Name": "my-service.my-namespace.",
"Type": "SRV",
"SetIdentifier": "4b46cb82ba434dasdb163c1f06ca5c083",
"MultiValueAnswer": true,
"TTL": 60,
"ResourceRecords": [
{
"Value": "1 1 27017 4b46cb82ba434dasdb163c1f06ca5c083.my-service.my-namespace."
}
],
"HealthCheckId": "862bd287-2b41-43ac-8442-a3d27042482b"
},
So i need to manually look up the record each time a service is created, or updated. I cannot dig
my-service.my-namespace for example, that record does not exist.
And:
2. every time the service is updated, the record is regenerated...
To get here i need to do:
$ aws servicediscovery list-namespaces
$ aws route53 list-resource-record-sets --hosted-zone-id $ZONE_ID --region us-east-1
My application currently accesses task hosts via injected environment variables, but if the record refreshes on every service update, this is a non starter. All documentation/forums I've come across seem to say, create some kind of dynamic SRV lookup workaround (seems hackish?) or just switch to awsvpc mode, but then why is this service available at all under bridge/host?
Clearly I'm missing something fundamental.
In addition I'm using dynamic port mapping. If I don't, things like rolling updates fail with port already in use errors. Similarly attempting to run a new instance of a task via scheduling creates the same error.
I can connect within a given docker container in a task with the internal private DNS of the instance, i.e. ip-172-31-52-141.ec2.internal, but here I'm outside of the VPC (?) i.e. now I need to be specifying the dynamically mapped port. So this is a non starter as well.
All of this sits behind a public ALB (for dynamic port resolution etc), and this has been working fine, requests from outside AWS resolve correctly to the target groups / targeted services.
If I switch to awsvpc mode, and enable service discovery, I can have multiple tasks/services communicate privately.
However what if I want to have multiple services communicate, but additionally a single service/task might house multiple docker containers, (e.g. a localized redis cache). I cannot specify the 'link' for these containers without the network mode being 'bridge' again.
here's the TLDR question:
I have 2 tasks and a service associated with each task. There may be multiple instances of each task, therefore ports need to be dynamic. In each task i have 2 containers.
What is the general approach here for allowing different services to communicate via a predefined host.namespace dns resolution, and have the containers inside each task communicate with each other?
Apologies for the long post, but as a novice to ECS/AWS, I'm really struggling here ;)
Any feedback or advice is really appreciated.
I need to create a dynamic number of subdomains depending on how many instances I want to create. my goal id to create something like
customer-code-100.example.com
customer-code-101.example.com
customer-code-102.example.com
customer-code-103.example.com
I've researched, but there doesn't seem to be a solution. I need to be able to run Puppet on multiple hosts, but they each need a different domain.
Ideally, I want to be able to use autoscaling or some sort of dynamic way to accomplish this, but I haven't been able to find any answers.
MyRecordSet:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: example.com.
Name: !Join[".", [!Ref Alias, "example.com"]]
Type: A
The easier method is to have the instances register themselves with Amazon Route 53. This can be done with a startup script that uses the AWS CLI to register a domain name.
Admittedly, it can be hard to decide which number to assign an instance, especially if Auto Scaling is being used. For example:
If Instance 1 and Instance 2 exist, obviously the next is Instance 3
But if Instance 2 is terminated by Auto Scaling and only Instance 1 and Instance 3 exist, should the next instance be Instance 2 or Instance 4?
Or, use part of the Instance ID to generate the name.
Then there is the problem of "unregistering" a subdomain when the instance is terminated.
Actually, there should normally be no need to assign a subdomain to an Auto Scaling instance. This is because traffic is normally routed through a Load Balancer, or the instances are pulling work from a queue. There should be no need to uniquely address a specific instance.
I'm using Terraform to spin-up my infrastructure on AWS and keep state in the .tfstate file. In my application I have to VPN into other networks where the admin of the other network has defined parameters on the IPSec ESP connection that the VPN connection on my end has to adhere to.
Using Terraform I create a VPN Gateway and a Customer Gateway with the remote network's parameters to the extent that's possible. Then I create a VPN connection and the appropriate route. Here's my VPN code in Terraform:
resource "aws_vpn_gateway" "vpn_gw" {
vpc_id = "${aws_vpc.default.id}"
tags {
Name = "default"
Terraform = true
}
}
resource "aws_customer_gateway" "customer_gw" {
bgp_asn = 65000
ip_address = "172.0.0.1"
type = "ipsec.1"
}
resource "aws_vpn_connection" "default" {
vpn_gateway_id = "${aws_vpn_gateway.vpn_gw.id}"
customer_gateway_id = "${aws_customer_gateway.customer_gw.id}"
type = "ipsec.1"
static_routes_only = true
}
resource "aws_vpn_connection_route" "office" {
destination_cidr_block = "192.168.10.0/24"
vpn_connection_id = "${aws_vpn_connection.default.id}"
}
I have to be able to set the following parameters on my VPN tunnel for phase 1 and phase 2 of the connection:
Phase 1
Authentication Method e.g. Pre-shared Secret
Encryption Scheme e.g. IKE
Diffie-Hellman Group e.g. Group 2
Encryption Algorithm e.g. AES-256
Hashing Algorithm e.g. SHA-1
Main or Aggressive Mode e.g. Main Mode
Lifetime (for renegotiation) e.g. 86400
Phase 2
Encapsulation (ESP or AH) e.g. ESP
Encryption Algorithm e.g. AES-256
Authentication Algorithm e.g. SHA-1
Perfect Forward Secrecy e.g. NO-PFS
Lifetime (for renegotiation) e.g. 3600
The docs on the VPN Customer Gateway show that you can't set that many parameters yourself: https://www.terraform.io/docs/providers/aws/r/customer_gateway.html
The Boto API also doesn't allow any additional parameters to be set.
Is there any way of setting these parameters (programmatically)?
Unfortunately, the answer to your question is no. This isn't a Terraform issue, as such, this is a limitation of the service provided by AWS. You don't get that level of configuration with AWS's basic solution.
To achieve what you are looking for, you'll need to spin up an EC2 instance and either
Roll your own using OpenSwan, VyOS, etc., e.g., https://aws.amazon.com/marketplace/pp/B00JK5UPF6 (just the AWS costs)
Use a VPN appliance from the AWS marketplace, e.g., https://aws.amazon.com/marketplace/pp/B00OCG4OAA (you'll need to pay a licensing fee to the vendor, as well as your AWS costs)
From a brief search - there does not seem to be a method to set dynamic hostnames for members of an autoscaling group. The functionality exists within OpenStack Heat using index - but I cannot find anything on doing so with AWS autoscaling groups.
For example, using OpenStack Heat - nodes are automatically given a hostname based on the number of nodes in the autoscaling group:
instance_group:
type: OS::Heat::ResourceGroup
properties:
count: { get_param: instance_number }
resource_def:
type: OS::Nova::Server
properties:
name: instance%index%
Would give me the following if I were to have 3 instances in the autoscaling group
instance0
instance1
instance2
Is there a similar method I can use with the AWS autoscaling groups launch configuration and or cloud-init?
I've found a solution that works pretty well, if you stick to some not-unreasonable conventions.
Every kind of EC2 instance that I launch, whether there are N servers of this kind in an autoscaling group or it's stand-alone instance, I create an Instance Profile for it. This is a good idea anyway in my experience, even if you don't need the instance to access any aws services it doesn't hurt to have a role/profile with empty permissions, it makes it that much easier to give it access to an s3 bucket or whatever else in the future if you need to.
Then at server launch in the user_data script (or your configuration management tool if you're using something like puppet or ansible), I query the instance profile name from the metadata service and append something unique to each server like the private ip and set that as the hostname.
You'll end up with hostnames like webserver-10-0-12-58 which is both human readable and unique to each server.
(The downside of this vs incrementing integers is that these aren't predictable, and can't be used to set up unique behavior for a single server. For example if you had webserver-{0-8} and needed to run some process on exactly one server, you could use logic like if hostname == webserver-0 then run_thing.)