VPC verified access using Pulumi

VPC verified access using Pulumi

As cloud environments continue to evolve, ensuring secure and streamlined network connectivity becomes paramount. Amazon Web Services (AWS) has introduced a new feature called VPC Verified Access, built on Zero Trust guiding principles, offering enhanced security and simplified access management for Virtual Private Cloud (VPC) resources. In this blog post, we will explore what VPC Verified Access is, its key features, and the use cases where it can be beneficial.

What is VPC Verified Access?

VPC Verified Access is a feature provided by AWS that enables secure access to resources within a VPC by leveraging client-side TLS certificates. It is built on Zero Trust principles, which assume that no network or user can be inherently trusted. With VPC Verified Access, organizations adopt a Zero Trust approach to network security, ensuring that every access request is verified and authorized, regardless of its origin or location.

Key Features of VPC Verified Access

Client-Side TLS Certificates

VPC Verified Access utilizes client-side TLS certificates for authentication and encryption. Clients are required to present a valid TLS certificate during the connection establishment process, ensuring that only authorized clients can access VPC resources. This approach aligns with the Zero Trust principle of authenticating and verifying every access attempt.

Secure Connectivity

By leveraging TLS encryption, VPC Verified Access ensures secure communication between clients and VPC resources. The encryption protects sensitive data in transit, guarding against eavesdropping or tampering attempts. This encryption layer adds an additional level of security, reducing the risk of data breaches and unauthorized access.

Simplified Access Management

With VPC Verified Access, managing access to VPC resources becomes more streamlined. Instead of managing complex firewall rules or IP whitelists, administrators can focus on managing client certificates and associating them with the appropriate resources. This simplifies access control and reduces the administrative overhead, while adhering to the Zero Trust principle of least privilege.

Granular Access Control

VPC Verified Access provides fine-grained control over resource-level access. By associating specific client certificates with individual resources or groups of resources, administrators can enforce access policies based on the Zero Trust principle of granting access only when necessary. This ensures that each client has access only to the resources they require, minimizing the attack surface and enhancing overall security.

Use Cases for VPC Verified Access

Application-to-Application Communication

VPC Verified Access is well-suited for secure communication between applications running in different VPCs or across different AWS accounts. By authenticating and encrypting communication using client-side TLS certificates, organizations can establish secure connections between their distributed applications without the need for complex VPN setups. This approach aligns with the Zero Trust principle of verifying and securing all communication channels.

Third-Party Integration:

When integrating with external partners or vendors, organizations can leverage VPC Verified Access to establish secure connections. By exchanging client-side TLS certificates with trusted partners, organizations can ensure that only authorized entities can access their VPC resources, minimizing the risk of unauthorized access. This use case follows the Zero Trust principle of verifying the identity and authorization of all entities, including third parties.

Secure API Gateway Access

VPC Verified Access can be used to secure access to API Gateway endpoints deployed within a VPC. By requiring client-side TLS certificates, organizations can authenticate and authorize incoming requests to their APIs, mitigating the risks associated with unauthorized access or API abuse. This approach aligns with the Zero Trust principle of securing all access points and validating each request.

Architecture Overview

We will explore the power of VPC Verified Access by demonstrating a simple architecture using an EC2 instance fronted by an Application Load Balancer (ALB). We will leverage the capabilities of Pulumi, an infrastructure as code platform, to create this stack. Furthermore, we will highlight the significance of VPC Verified Access, emphasizing its availability on Pulumi while other popular platforms like Terraform are yet to release an official version.

Code

https://github.com/dishu2511/vpc-verified-access

The code is structured into four main parts, each serving a specific purpose:

  1. Declaring Environment Variables and Creating Cedar Policy: In this part, we define the necessary environment variables required for the deployment. Additionally, we create a Cedar policy, which is a set of access control rules that govern the permissions and actions allowed within the deployment.
  2. Creating EC2 Stack: This section focuses on creating the EC2 stack, which includes provisioning EC2 instances and configuring their associated resources such as security groups, key pairs, and storage. The EC2 stack forms the backbone of the infrastructure.
  3. Creating ALB Stack: The ALB stack involves setting up an Application Load Balancer (ALB) to distribute incoming traffic across the EC2 instances. This stack handles load balancing, health checks, and routing of requests to ensure high availability and optimal performance.
  4. Creating VPC Verified Stack: The VPC Verified stack is responsible for enabling VPC Verified Access, a feature that enhances network security by restricting access to AWS resources only from trusted VPCs. This stack configures the necessary VPC settings and establishes the appropriate connectivity for secure access.

By dividing the code into these distinct parts, it becomes easier to manage and understand each component's functionality and purpose within the overall deployment architecture.

Declaring environment variables and creating cedar policy

# defining config file
with open("./config.json") as config_file:
? ? data = json.load(config_file)


# defining userdata file
with open("userdata.sh", "r") as file:
? ? user_data_script = file.read()


# decalaring env variables
STACK_NAME = data["STACK_NAME"]
PRIVATE_SUBNET_IDS = data["PRIVATE_SUBNET_IDS"]
VPC_ID = data["VPC_ID"]
INSTANCE_TYPE = data["INSTANCE_TYPE"]
CLOUDWATCH_LOGS = data["CLOUDWATCH_LOGS"]
AMI = data["AMI"]
DOMAIN = data["DOMAIN"]
APPLICATION_DOMAIN = data["APPLICATION_DOMAIN"]
POLICY_REF_NAME = data["POLICY_REF_NAME"]
EMAIL_DOMAIN = data["EMAIL_DOMAIN"]
GROUP_ID = data["GROUP_ID"]
HTTPS_PORT = data["HTTPS_PORT"]
HTTP_PORT = data["HTTP_PORT"]
PROTOCOL = data["PROTOCOL"]


# getting acm cert
ssl_cert = aws.acm.get_certificate(domain=DOMAIN, statuses=["ISSUED"])


# cedar policy
cedar_policy = """
? ? ? ? permit(principal, action, resource)
? ? ? ? when {
? ? ? ? ? ? context.{POLICY_REF_NAME}.groups has "{GROUP_ID}" &&
? ? ? ? ? ? context.{POLICY_REF_NAME}.user.email.address like "*@{EMAIL_DOMAIN}" &&
? ? ? ? ? ? context.{POLICY_REF_NAME}.user.email.verified == true
? ? ? ? };
? ? ? ? """
cedar_policy_env_vars = {
? ? "{POLICY_REF_NAME}": POLICY_REF_NAME,
? ? "{GROUP_ID}": GROUP_ID,
? ? "{EMAIL_DOMAIN}": EMAIL_DOMAIN,
}


for env_var, var_name in cedar_policy_env_vars.items():
? ? var_value = var_name
? ? if var_value:
? ? ? ? cedar_policy = re.sub(re.escape(env_var), var_value, cedar_policy)        

You must be wondering what is cedar policy now?

It ?is a authorization policy language used by customers of the Amazon Verified Permissions and AWS Verified Access managed services.?(link)

Creating ec2 stack


# function to create a stack for ec2
def ec2_stack():


? ? # creating a security group for ec2 instance
? ? ec2_sg = aws.ec2.SecurityGroup(
? ? ? ? f"{STACK_NAME}-ec2-sg",
? ? ? ? vpc_id=VPC_ID,
? ? ? ? ingress=[
? ? ? ? ? ? aws.ec2.SecurityGroupIngressArgs(
? ? ? ? ? ? ? ? from_port=HTTP_PORT,
? ? ? ? ? ? ? ? to_port=HTTP_PORT,
? ? ? ? ? ? ? ? protocol=PROTOCOL,
? ? ? ? ? ? ? ? cidr_blocks=["0.0.0.0/0"],
? ? ? ? ? ? )
? ? ? ? ],
? ? ? ? egress=[
? ? ? ? ? ? aws.ec2.SecurityGroupEgressArgs(
? ? ? ? ? ? ? ? from_port=0,
? ? ? ? ? ? ? ? to_port=0,
? ? ? ? ? ? ? ? protocol="-1",
? ? ? ? ? ? ? ? cidr_blocks=["0.0.0.0/0"],
? ? ? ? ? ? )
? ? ? ? ],
? ? ? ? tags={
? ? ? ? ? ? "Name": f"{STACK_NAME}-ec2-sg",
? ? ? ? },
? ? )


? ? # creating a sample ec2 instance which wil be fronted by alb
? ? ec2_instance = aws.ec2.Instance(
? ? ? ? f"{STACK_NAME}-ec2",
? ? ? ? instance_type=INSTANCE_TYPE,
? ? ? ? subnet_id=PRIVATE_SUBNET_IDS[0],
? ? ? ? vpc_security_group_ids=[ec2_sg.id],
? ? ? ? ami=AMI,
? ? ? ? user_data=user_data_script,
? ? ? ? tags={
? ? ? ? ? ? "Name": f"{STACK_NAME}-ec2",
? ? ? ? },
? ? )
? ? return (ec2_sg, ec2_instance)        

Creating ALB stack


# function to create a stack for alb
def alb_stack(ec2_sg_id, ec2_instance_id):


? ? # creating a security group for alb instance
? ? alb_sg = aws.ec2.SecurityGroup(
? ? ? ? f"{STACK_NAME}-alb-sg",
? ? ? ? vpc_id=VPC_ID,
? ? ? ? ingress=[
? ? ? ? ? ? aws.ec2.SecurityGroupIngressArgs(
? ? ? ? ? ? ? ? from_port=HTTPS_PORT,
? ? ? ? ? ? ? ? to_port=HTTPS_PORT,
? ? ? ? ? ? ? ? protocol=PROTOCOL,
? ? ? ? ? ? ? ? cidr_blocks=["0.0.0.0/0"],
? ? ? ? ? ? )
? ? ? ? ],
? ? ? ? egress=[
? ? ? ? ? ? aws.ec2.SecurityGroupEgressArgs(
? ? ? ? ? ? ? ? from_port=0,
? ? ? ? ? ? ? ? to_port=0,
? ? ? ? ? ? ? ? protocol="-1",
? ? ? ? ? ? ? ? cidr_blocks=["0.0.0.0/0"],
? ? ? ? ? ? )
? ? ? ? ],
? ? ? ? tags={
? ? ? ? ? ? "Name": f"{STACK_NAME}-alb-sg",
? ? ? ? },
? ? )


? ? ec2_sg_rule = aws.ec2.SecurityGroupRule(
? ? ? ? f"{STACK_NAME}-ec2-sg-rule",
? ? ? ? type="ingress",
? ? ? ? from_port=HTTP_PORT,
? ? ? ? to_port=HTTP_PORT,
? ? ? ? protocol=PROTOCOL,
? ? ? ? source_security_group_id=alb_sg,
? ? ? ? security_group_id=ec2_sg_id,
? ? )


? ? # creating an internal ALB
? ? load_balancer = aws.alb.LoadBalancer(
? ? ? ? f"{STACK_NAME}-alb",
? ? ? ? name=f"{STACK_NAME}-alb",
? ? ? ? internal=True,
? ? ? ? load_balancer_type="application",
? ? ? ? security_groups=[alb_sg.id],
? ? ? ? subnets=PRIVATE_SUBNET_IDS,
? ? ? ? tags={
? ? ? ? ? ? "Name": f"{STACK_NAME}-alb",
? ? ? ? },
? ? )


? ? # creating a target group with target type 'instance'
? ? target_group = aws.alb.TargetGroup(
? ? ? ? f"{STACK_NAME}-tg",
? ? ? ? port=HTTP_PORT,
? ? ? ? protocol="HTTP",
? ? ? ? target_type="instance",
? ? ? ? vpc_id=VPC_ID,
? ? ? ? tags={
? ? ? ? ? ? "Name": f"{STACK_NAME}-tg",
? ? ? ? },
? ? )


? ? # attaching the EC2 instance to the target group
? ? target_group_attachment = aws.alb.TargetGroupAttachment(
? ? ? ? f"{STACK_NAME}-tg-attachment",
? ? ? ? target_group_arn=target_group.arn,
? ? ? ? target_id=ec2_instance_id,
? ? ? ? port=HTTP_PORT,
? ? )
? ? # creating a listener
? ? listener = aws.alb.Listener(
? ? ? ? f"{STACK_NAME}-listener",
? ? ? ? load_balancer_arn=load_balancer.arn,
? ? ? ? port=HTTPS_PORT,
? ? ? ? protocol="HTTPS",
? ? ? ? ssl_policy="ELBSecurityPolicy-TLS13-1-2-2021-06",
? ? ? ? certificate_arn=ssl_cert.arn,
? ? ? ? default_actions=[
? ? ? ? ? ? {
? ? ? ? ? ? ? ? "type": "forward",
? ? ? ? ? ? ? ? "target_group_arn": target_group.arn,
? ? ? ? ? ? }
? ? ? ? ],
? ? )
? ? return load_balancer        

Creating VPC verified stack

Finally, we create the VPC Verified stack, which primarily focuses on enabling VPC Verified Access. However, there are a few important considerations to keep in mind:

  1. Valid Domain Requirement: VPC Verified Access is only applicable to valid domains. Therefore, if you intend to test or perform a Proof of Concept (POC), you must have a verified domain and an AWS Certificate Manager (ACM) certificate that is valid for that domain.
  2. Identity Provider (IDP) Selection: In this setup, AWS Single Sign-On (SSO) is used as the Identity Provider. To select AWS SSO as the IDP, choose the "iam-identity-center" option when configuring the VPC Verified stack.
  3. Once, the VPC verified access endpoint is create, please use the DNS name and create a CNAME record pointing at application DNS name.

Please Note: It's crucial to ensure that the "POLICY_REF_NAME" environment variable matches the "policy_reference_name" when creating the Cedar policy and configuring the trust provider. This is an important detail that can sometimes be overlooked and may result in unexpected behavior. I personally encountered this issue and spent a significant amount of time troubleshooting before realizing the mismatched names.


# function to create a stack for voc verified access
def vpc_verified_access(load_balancer_arn):
? ? # creating a security group for vpc verified access
? ? vpc_verified_access_sg = aws.ec2.SecurityGroup(
? ? ? ? f"{STACK_NAME}-sg",
? ? ? ? vpc_id=VPC_ID,
? ? ? ? ingress=[
? ? ? ? ? ? aws.ec2.SecurityGroupIngressArgs(
? ? ? ? ? ? ? ? from_port=HTTPS_PORT,
? ? ? ? ? ? ? ? to_port=HTTPS_PORT,
? ? ? ? ? ? ? ? protocol=PROTOCOL,
? ? ? ? ? ? ? ? cidr_blocks=["0.0.0.0/0"],
? ? ? ? ? ? )
? ? ? ? ],
? ? ? ? egress=[
? ? ? ? ? ? aws.ec2.SecurityGroupEgressArgs(
? ? ? ? ? ? ? ? from_port=0,
? ? ? ? ? ? ? ? to_port=0,
? ? ? ? ? ? ? ? protocol="-1",
? ? ? ? ? ? ? ? cidr_blocks=["0.0.0.0/0"],
? ? ? ? ? ? )
? ? ? ? ],
? ? ? ? tags={
? ? ? ? ? ? "Name": f"{STACK_NAME}-sg",
? ? ? ? },
? ? )
? ? # creating a cloudwatch log group for vvpc verified access
? ? cloudwatch_log_group = aws.cloudwatch.LogGroup(
? ? ? ? f"{STACK_NAME}-log-group",
? ? ? ? tags={
? ? ? ? ? ? "Name": f"{STACK_NAME}-log-group",
? ? ? ? },
? ? )


? ? # creating vpc verified access stack
? ? trust_provider = aws_native.ec2.VerifiedAccessTrustProvider(
? ? ? ? f"{STACK_NAME}-trust-provider",
? ? ? ? policy_reference_name=POLICY_REF_NAME,
? ? ? ? trust_provider_type="user",
? ? ? ? user_trust_provider_type="iam-identity-center",
? ? ? ? tags=[
? ? ? ? ? ? aws_native.ec2.VerifiedAccessTrustProviderTagArgs(
? ? ? ? ? ? ? ? key="Name",
? ? ? ? ? ? ? ? value=f"{STACK_NAME}-trust-provider",
? ? ? ? ? ? )
? ? ? ? ],
? ? )
? ? verified_access_instance = aws_native.ec2.VerifiedAccessInstance(
? ? ? ? f"{STACK_NAME}-instance",
? ? ? ? verified_access_trust_provider_ids=[trust_provider],
? ? ? ? logging_configurations=aws_native.ec2.VerifiedAccessInstanceVerifiedAccessLogsArgs(
? ? ? ? ? ? cloud_watch_logs=aws_native.ec2.VerifiedAccessInstanceVerifiedAccessLogsCloudWatchLogsPropertiesArgs(
? ? ? ? ? ? ? ? enabled=CLOUDWATCH_LOGS, log_group=cloudwatch_log_group
? ? ? ? ? ? )
? ? ? ? ),
? ? ? ? tags=[
? ? ? ? ? ? aws_native.ec2.VerifiedAccessInstanceTagArgs(
? ? ? ? ? ? ? ? key="Name",
? ? ? ? ? ? ? ? value=f"{STACK_NAME}-instance",
? ? ? ? ? ? )
? ? ? ? ],
? ? )
? ? verified_access_group = aws_native.ec2.VerifiedAccessGroup(
? ? ? ? f"{STACK_NAME}-group",
? ? ? ? verified_access_instance_id=verified_access_instance,
? ? ? ? policy_document=cedar_policy,
? ? ? ? tags=[
? ? ? ? ? ? aws_native.ec2.VerifiedAccessGroupTagArgs(
? ? ? ? ? ? ? ? key="Name",
? ? ? ? ? ? ? ? value=f"{STACK_NAME}-group",
? ? ? ? ? ? )
? ? ? ? ],
? ? )
? ? verified_access_endpoint = aws_native.ec2.VerifiedAccessEndpoint(
? ? ? ? f"{STACK_NAME}-endpoint",
? ? ? ? application_domain=APPLICATION_DOMAIN,
? ? ? ? domain_certificate_arn=ssl_cert.arn,
? ? ? ? endpoint_domain_prefix=STACK_NAME,
? ? ? ? verified_access_group_id=verified_access_group,
? ? ? ? attachment_type="vpc",
? ? ? ? endpoint_type="load-balancer",
? ? ? ? security_group_ids=[vpc_verified_access_sg],
? ? ? ? load_balancer_options=aws_native.ec2.VerifiedAccessEndpointLoadBalancerOptionsArgs(
? ? ? ? ? ? load_balancer_arn=load_balancer_arn,
? ? ? ? ? ? port=HTTPS_PORT,
? ? ? ? ? ? protocol="https",
? ? ? ? ? ? subnet_ids=PRIVATE_SUBNET_IDS,
? ? ? ? ),
? ? ? ? tags=[
? ? ? ? ? ? aws_native.ec2.VerifiedAccessEndpointTagArgs(
? ? ? ? ? ? ? ? key="Name",
? ? ? ? ? ? ? ? value=f"{STACK_NAME}-endpoint",
? ? ? ? ? ? )
? ? ? ? ],
? ? )        

Finally executing the 3 functions

ec2 = ec2_stack()
alb = alb_stack(ec2[0], ec2[1])
vpc_verified_access(alb.arn)        

Testing

One noticeable aspect is that when attempting to access the application, you will encounter an AWS SSO sign-in window.

No alt text provided for this image

Utilize your AWS SSO credentials to log in. After successful authentication, you will gain access to your application. If you are using the provided code, you can expect to see a result similar to the example below:

No alt text provided for this image


Overall, I found VPC Verified Access to be a remarkable solution that greatly simplifies the setup process and alleviates many challenges. It streamlines the configuration steps and eliminates unnecessary complexities, making it a hassle-free experience. With VPC Verified Access, I was able to focus more on building and securing my applications, rather than getting bogged down by intricate authentication and authorization mechanisms.

要查看或添加评论,请登录

Dinesh Sharma的更多文章

  • GenAI Powered Chatbot Using Bedrock and Lex

    GenAI Powered Chatbot Using Bedrock and Lex

    Ever wondered how to build your own AI-powered chatbot without diving deep into the complexities of machine learning?…

  • From Bicycle to Spaceship: Navigating the Cloud Transformation Journey

    From Bicycle to Spaceship: Navigating the Cloud Transformation Journey

    Cloud transformation is like a journey one that takes you from the streets of your neighborhood to destinations far…

    6 条评论
  • re:Invent 2024: Day 4 Recap

    re:Invent 2024: Day 4 Recap

    Keynote Highlights from Werner Vogels: Lessons in "Simplexity" Werner Vogels’ keynote at AWS re:Invent 2024 was, as…

  • re:Invent 2024 Day 3 Recap

    re:Invent 2024 Day 3 Recap

    It’s Day 3 of AWS re:Invent, and the cloud conference rollercoaster is in full swing! Today was extra special because…

  • re:Invent 2024: Day 2 Recap

    re:Invent 2024: Day 2 Recap

    After the excitement of Day 1 at AWS re:Invent, which I recapped yesterday, the momentum only picked up on Day 2! Today…

    1 条评论
  • re:Invent 2024: Day 1 Recap

    re:Invent 2024: Day 1 Recap

    AWS re:Invent isn’t just an event, it’s a full-blown tech carnival where innovation meets collaboration, sprinkled with…

  • Farewell to AWS Services: A Nerdy Goodbye

    Farewell to AWS Services: A Nerdy Goodbye

    Well, folks, it looks like AWS has decided to play the role of the grim reaper for some of its services. In a move that…

    1 条评论
  • Drawing AWS with Python (No Art Skills Required)

    Drawing AWS with Python (No Art Skills Required)

    Gone are the days when updating architecture diagrams was a tedious task that often got pushed to the back burner In…

    5 条评论
  • Schedule Your Fargate Pods Organization-Wide Using a magic Lambda

    Schedule Your Fargate Pods Organization-Wide Using a magic Lambda

    Spoiler Alert! There are no magic Lambdas here, just a carefully crafted Lambda function designed to automate the…

  • Scaling Deployments with AWS Lambda

    Scaling Deployments with AWS Lambda

    Hello LinkedIn :) Recently, I've had the pleasure of diving deep into a fascinating use-case involving AWS Lambda and…

社区洞察

其他会员也浏览了