I'm trying to write a Python task to (re)issue a certificate from inside a Fargate task. This has proven to be more daunting than I anticipated, but I'm making progress. The basic idea is that I have an ALB that has listeners for ports 443 and 80. The port 443 listener has the certificate, the port 80 listener redirects traffic to a target group which points to my task. The task is launched by:
aws ecs run-task --cluster myCluster --launch-type FARGATE \
--task-definition certbot-task:2 \
--network-configuration '{
"awsvpcConfiguration":
{ "assignPublicIp":"ENABLED",
"securityGroups": ["sg-mysg"],
"subnets": ["subnet-mysubnet"]}
}'
The task figures out what privateIPv4Address and availabilityZone mysubnet points at and registers a target:
newtargets = [{'Id': privateIPv4Address,'Port': 80,'AvailabilityZone': availabilityZone}]
response = elb_client.register_targets(TargetGroupArn=tg_arn,Targets=newtargets)
This works, but the problem is that the target is not available yet:
TargetHealth = elb_client.describe_target_health(TargetGroupArn=tg_arn,Targets=newtargets)['TargetHealthDescriptions'][0]['TargetHealth']
print(f"TargetHealth: {TargetHealth}")
TargetHealth: {'State': 'initial', 'Reason': 'Elb.RegistrationInProgress', 'Description': 'Target registration is in progress'}
No problem, I fire up a socket listener on port 80 and return 'HTTP/1.0 200 OK\n\nOK' for 'GET /', the target becomes healthy, and I can respond to curl from an external address. So now I'm ready to call certbot.main() to get my certificate, but I have one minor problem; if I don't respond to my health checks, the target listener will die an ignoble death. I can see 3 possibilities:
- Release port 80 and run certbot --standalone, hoping that the server asks for the challenge before my next health check comes along
- Keep listening to the socket and return the challenge myself by running certbot --webroot
- Bring up nginx in my container and let it handle both health checks and authentication.
I haven't figured out how --standalone works, but I can't see the security risk of the standalone sever responding with 'HTTP/1.0 200 OK\n\nOK' in response to 'GET /'. I'd prefer not to use 3), as I'm trying to keep the Docker image small. 2) will probably require the socket listener to be in a subprocess.
Before I started working on this, I wondered why no one had done this before. Now I know. I get that I can get a certificate for an Amazon-managed domain, but that isn't an option for me right now. Suggestions?