The CIS security best practices for AWS (4.1) recommends that Port 22 has no public incoming traffic (0.0.0.0/0), so a problem arises when trying to access instances via SSH. A possible solution to this would be manually adding permissions (access from a specified IP address for example) to an instance’s security group, but this could be very error prone and inconsistent as people could forget to remove permissions or remove the wrong permissions.
Some enterprises deal with this issue by having people VPN into their corporate network and having people SSH from there. However, this doesn’t make sense for many distributed organizations where there is no VPN or where granting access to a VPN would grant too broad access for those who need to SSH into a class of AWS EC2 instances. These two approaches both present possible security risks and are susceptible to human error.
AWS provides some possible solutions to this issue including EC2 Instance Connect and Sessions Manager via AWS Systems Manager. EC2 Instance Connect uses a temporary SSH key (with a 60 second lifetime) to authenticate and an IAM policy to allow access from IAM users in the same organization. Session Manager is also a viable alternative, but requires users to have IAM account access. Both of these are valid ways to temporarily SSH into EC2 instances but neither of these approaches allow for SAML and integration with Web providers and there are still some areas prone to human error.
Clearly, there is room for improvement and making life easier for developers working with EC2.
AWS Acme Instant Tunnel presents an alternative to the aforementioned approaches by automating the authorization, management and storage of security group permissions for temporary SSH access. This application is built on the Serverless framework, which is a great tool that integrates with AWS CloudFormation and manages all the underlying infrastructure (Lambda functions, DynamoDB tables, EC2 security groups, S3 bucket hosting, IAM roles, and API Gateway).
The diagram above depicts the following. In simple terms, a user will sign in and upon successful authentication, a temporary permission will be added to a security group and information stored in a database. Upon expiry of the permission, the temporary permission will be revoked.
DynamoDB is used to store user information and temporary security group permissions (“leases”). The user authorization and authentication is done using Auth0 SAML integration. Upon successful login, an AWS Lambda function is triggered to add lease information to DynamoDB and create security group ingress permissions for the user’s IP address. TTL is enabled on the lease end timestamp, meaning that the DynamoDB table will automatically update and delete the expired entry. Upon deletion, a DynamoDB stream triggers a separate Lambda function which will revoke security group ingress permissions for the expired lease.
A Quick Demo
A basic frontend demo can be found here.
The site is deployed on S3 bucket static website hosting. Users must log in to be able to gain temporary SSH access.
Users are authenticated and authorized through Auth0. Different Identity Providers are configurable but by default Google G-Suite is available.
After authentication, users are now able to Tunnel into EC2. Upon successful completion, a success message of “You can now SSH into the EC2 instance for 1 hour” is generated.
Behind the Scenes
An item with lease start and end time, user IP address, and email address are added to DynamoDB table. The timestamps are in seconds since Epoch format. A corresponding security group ingress permission is added. The user can now SSH into this instance.
The DynamoDB table has TTL enabled on the leaseEnd attribute. When the leaseEnd attribute is expired, the item will automatically delete itself and will also revoke the corresponding security group ingress permission. The user now cannot SSH into this instance.
Getting Started: Customization & Deployment
- Make sure you have the AWS CLI installed and that AWS credentials are properly configured before starting. You can do this by running aws configure on the command line.
- Clone this repository, change directory to it, and run
- Go to Auth0 and sign up for an account. Go to Applications and click on your Default App. Here you can find your Auth0 development credentials for the next steps. Save the Client ID and Domain.
- Edit the
secrets.json fileand replace
AUTH0_CLIENT_IDwith the Client ID found in the previous step.
- Go back to Auth0 Application settings and click on Show Advanced Settings -> Certificates. Copy and paste the Signing Certificate into the
AUTH0_CLIENT_IDwith the Client ID and
AUTH0_DOMAIN` with the Domain found in Step 3. Replace
leaseTimewith the desired time for temporary SSH permissions in seconds
- Edit the
serverless.yml filewhere you will need to change the environment variables under provider -> environment section.
VPC_IDto your vpc id. You can find it in the AWS Console in the VPC section under Your VPCs.
USER_AWS_REGIONto the region you want to deploy resources in.
S3_BUCKET_NAMEto something unique. An error will be thrown if the S3 bucket name is already taken.
sls deployat the command line.
- A URL will be generated under endpoints if deployment runs successfully. In app.js, replace
PRIVATE_ENDPOINTwith this URL. Run
sls client deployand type Y when prompted. This updates and deploys the front-end.
- With a successful front-end deployment, you should get an S3 URL where the web app is hosted. Copy this URL and go to Auth0 settings. Find Allowed Callback URIs under Application URIs and paste the S3 URL into this box. Make sure to Save Changes at the bottom.
- Open the AWS Console and go to the EC2 instances section. Launch an EC2 instance (any storage or instance type settings are fine). Configure an existing security group and select the acme-instant-tunnel group that was generated during deployment. Generate and key pair and make sure to keep track of the key pair for when you want to SSH into the instance.
- Navigate to the S3 URL that was generated in Steps 9-10. You should be able to login and click Tunnel into EC2 with a success message ‘You can now SSH into the EC2 instance for 1 hour’. After this, you can try to connect to the EC2 instance via SSH and it should work.
This project would not have been possible without the help of the Modus Labs open-source team. A special shoutout to Richard Bullington-McGuire for coming up with the idea for this project and for guidance through development and documentation. If you have feedback about the project please create an issue on GitHub and someone from the Modus Labs open source team will respond.
- Promoting New Blog Entries with AWS Lambda and Slack
Here at Modus Create, we're avid users of Slack as a team collaboration tool and…
- How to Track Multiple Git Branches in AWS CodePipeline
CodePipeline is an impressive CI/CD service by AWS. Architect Lucas Still outlines best practices and…