# Deployment Details

We offer a number of flexible deployment options based on what you need. This includes:

* The `Standard Deployment` which requires filling out only 5 fields in the CloudFormation Template
* This also includes a completely `Private Deployment` where all of our components run in private VPCs and private Subnets with no public IPs assigned at all
* An in-between option where you have public access (public Load Balancer) while still running all solution components in a private VPC and Subnets

You can mix and match as well as incorporate VPC Endpoints to keep as much traffic as possible going over the AWS backbone.

{% hint style="warning" %}
All components deployed, created and installed run inside of your account. We do not host any of them and we never send any of your objects/files outside of your account. All scanning is performed close to the data inside your account(s) and in-region.

Our console requires specific permissions to manage its own infrastructure and integrate with your AWS services. To provide the most secure environment, we recommend deploying it in a dedicated AWS account. This isolates the product's permissions and prevents any unintended impact on other resources.

As you'll learn below, we may send some data (IP address, account email, version numbers) to a Cloud Storage Security AWS account to assist you and your users with accessing your application. ***You can opt out of this if you don't want that information to be reported.***

No matter the deployment option you choose, you can also leverage local signature updates for both the Sophos engine and the ClamAV engine through our [private mirror functionality](https://help.cloudstoragesec.com/console-overview/configuration/scan-settings#private-mirror-local-signature-updates).
{% endhint %}

## Standard Deployment

The `Standard Deployment` is the simplest deployment. After providing only 5 inputs to the CloudFormation Template you will have a deployed and running solution in \~5 minutes. This deployment expects the Console and the Agent(s) to be placed in VPCs and Subnets that have an Internet Gateway (IGW) allowing for outbound traffic.

This a typical setup for VPCs and Subnets.The outbound routing allows ECS to pull down images from ECR, allows the Console and Agent(s) to communicate with required AWS Services and provides access to the management UI. Although public IPs are assigned, control is still done through Security Groups and access can be limited through IP ranges.

With this deployment, we register your application subdomain with a Route53 Hosted Zone we host and manage in one of the Cloud Storage Security AWS accounts. This allows you to have consistent access to your application. If you'd prefer to manage the domain and SSL cert yourself, you can leverage the Application Load Balancer options discussed below.

{% tabs %}
{% tab title="Standard Deployment: 'Public Routing'" %}

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2FtAxWkNWGnV4UiPE5epR2%2Fdeployment-public-singleregion.png?alt=media&#x26;token=77bd599f-493d-49d2-a21f-f71b491b7c8d" alt=""><figcaption><p>Standard Deployment Single Region</p></figcaption></figure>
{% endtab %}

{% tab title="Standard Multi-Region Deployment: \`Public Routing'" %}

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2Fi5aotdU2zkOtaCmrc5ph%2Fdeployment-public-multiregion.png?alt=media&#x26;token=ef7214c1-2107-4ef7-8a13-bdfc61398f7e" alt=""><figcaption><p>Standard Deployment Multi Region</p></figcaption></figure>
{% endtab %}
{% endtabs %}

## Private Deployment

`Private Deployments` are defined by locking down the solution components (Console and Agents) such that they do not have public IPs. You can still provide public access if desired while locking everything else down. Whether it is best practices, compliance or internal rules you can deploy and leverage the solution as needed.

You'll see the deployment options below leveraging Application Load Balancers. These can be `internet-facing` or `internal` and can even be leveraged with the `Standard Deployment`. You do not have to leverage an ALB in a private deployment, but there are a number of reasons you might want to.

First off, AWS Fargate tasks do not get assigned persistent IP addresses. As a result, the IP address can change underneath you requiring you to look it up. You may also decide you'd like to manage or apply your own domain and SSL certificate for accessing the application. A load balancer allows you to accomplish all of these things: a persistent access point, apply your own domain and leverage your own certificates.

### Public Load Balancer Option

With this option we deploy an `internet-facing` load balancer on your behalf that will be publicly available based on your Security Group rules. Easy access over HTTPs.

{% tabs %}
{% tab title="Public LB with Private Console and Agent(s)" %}

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2FysyUGXkUWOVgnrgElpt3%2Fdeployment-public-lb-singleregion.png?alt=media&#x26;token=63d6b04a-e189-4ce3-bf78-864d3497914e" alt=""><figcaption><p>Private LB Single Region</p></figcaption></figure>
{% endtab %}

{% tab title="Public LB with Private Console and Agent(s) - Multi-Region" %}

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2FLAGngsKc6eeDW3sgkkHy%2Fdeployment-public-lb-multiregion.png?alt=media&#x26;token=bafa57ce-36da-47ac-af17-639cccf2a04c" alt=""><figcaption><p>Private LB Multi Region</p></figcaption></figure>
{% endtab %}
{% endtabs %}

### Private Load Balancer Option

With this option we deploy an `internal` load balancer on your behalf that will be assigned only internal/private IPs. You must be able to access this network, typically through VPN or Direct Connect, in order to access the application.

{% tabs %}
{% tab title="Private LB with Private Console and Agent(s)" %}

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2FJYlAIErveQx7Lt9wMwnl%2Fdeployment-private-lb-singleregion.png?alt=media&#x26;token=0435a31f-d9d7-4463-89df-c8544ce25d03" alt=""><figcaption><p>Private LB Single Region</p></figcaption></figure>
{% endtab %}

{% tab title="Private LB with Private Console and Agent(s) - Multi-Region" %}

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2FAKft5WHYueLuWrKMhVMw%2Fdeployment-private-lb-multiregion.png?alt=media&#x26;token=7a98c69a-97ec-4527-b8a7-7b49e0cd4685" alt=""><figcaption><p>Private LB Multi Region</p></figcaption></figure>
{% endtab %}
{% endtabs %}

## Leveraging VPC Endpoints

In the previous deployment options you either assigned public or private IPs to the solution components and you controlled their privacy by utilizing either an Internet Gateway or a NAT Gateway. In either scenario, all AWS API calls went out over the internet. There are times when you may want to limit internet traffic as much as possible. For this use case, AWS provides VPC Endpoints to keep the API call traffic on the AWS backbone, not over the open internet. VPC Endpoints can be mixed and matched into any of the deployment options, public or private. Note that the application reaches out to some non-AWS endpoints and will still require external access for full functionality. However, this implementation is a great reduction in the amount of traffic over the public internet so it is worth considering.

{% hint style="warning" %}
**Important:** The Security Group associated with the endpoints **ecr.dkr** and **ecr.api** must have an inbound rule allowing all traffic from the CIDR range of the VPC. \
Also, the subnets used for the console must be the ones included in the VPC Endpoints,.
{% endhint %}

{% hint style="info" %}
Even though Marketplace has an endpoint now, need for access to AWS Marketplace can be bypassed if you choose to subscribe to our BYOL listing.

A VPC Endpoint for Security Hub is optional and only required if you choose to use our Security Hub integration.
{% endhint %}

<details>

<summary>Recommended VPC Endpoints</summary>

**Essential VPC Endpoints**

In the case that subnet traffic is restricted, access to the following VPC endpoints are necessary for our application to function. Replace {region} with your region where you are deployed.

| com.amazonaws.{region}.s3                      |
| ---------------------------------------------- |
| com.amazonaws.{region}.cognito-idp             |
| com.amazonaws.{region}.dynamodb                |
| com.amazonaws.{region}.sts                     |
| com.amazonaws.{region}.sqs                     |
| com.amazonaws.{region}.events                  |
| com.amazonaws.{region}.cloudformation          |
| com.amazonaws.{region}.sns                     |
| com.amazonaws.{region}.application-autoscaling |
| com.amazonaws.{region}.ec2                     |
| com.amazonaws.{region}.ecs                     |
| com.amazonaws.{region}.fsx                     |
| com.amazonaws.{region}.ebs                     |
| com.amazonaws.{region}.cloudtrail              |
| com.amazonaws.{region}.ecr.dkr                 |
| com.amazonaws.{region}.ecr.api                 |
| com.amazonaws.{region}.elasticfilesystem       |
| com.amazonaws.{region}.logs                    |
| com.amazonaws.{region}.autoscaling             |
| com.amazonaws.{region}.elasticloadbalancing    |
| com.amazonaws.{region}.ecs-agent               |
| com.amazonaws.{region}.ssm                     |
| com.amazonaws.{region}.monitoring              |
| com.amazonaws.{region}.kms                     |

**Situational VPC Endpoints**

The following endpoints are situational and dependent on your configuration.

| com.amazonaws.{region}.appconfigdata        | Only necessary if \<v9.00.000. After upgrading to v9.00.000 or above, you can remove this endpoint. |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| com.amazonaws.{region}.appconfig            | Only necessary if \<v9.00.000. After upgrading to v9.00.000 or above, you can remove this endpoint. |
| com.amazonaws.{region}.license-manager      | Only necessary if using PayGo or Private Offer. Not necessary in GovCloud / BYOL.                   |
| com.amazonaws.{region}.metering-marketplace | Only necessary if using PayGo or Private Offer. Not necessary in GovCloud / BYOL.                   |
| com.amazonaws.{region}.securityhub          | Only necessary if utilizing the Security Hub integration.                                           |

</details>

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2F0Jml7ZAyoA1HlSDXv8kh%2FCSS-Architecture-jl-vpc-endpoints-annotated-2025.drawio.png?alt=media&#x26;token=daa8813b-811b-481d-b3b4-7b2e457d9a8e" alt="Private Deployment with VPC Endpoints"><figcaption><p>Private Deployment with VPC Endpoints</p></figcaption></figure>

**Setting up a VPC Endpoints Deployment**

1. The user must configure either AWS Direct Connect, a VPN, or a jumpbox to access the private subnet.
2. All AWS services can be accessible over VPC Endpoint. The Console and Agent will attempt to contact all endpoint-enabled services using that method. All requests going through endpoints will be traveling over the AWS global network infrastructure.
3. For non-AWS endpoints, we require a customer-created proxy, which the Console and Agent will use to forward those requests to the configured NAT Gateway. Place the proxy in a private subnet in the same VPC where the stack is deployed. Once the proxy is up, use the 'proxy' and 'proxy port' parameters in CFT or Terraform to indicate where the application should look to contact the proxy.

{% hint style="info" %}

#### You can also use the following script to setup the Endpoints needed:

{% endhint %}

{% tabs %}
{% tab title="Python - Console VPC Endpoints Script" %}
Replace variables and awscli profile name

```python
import boto3

def create_vpc_endpoints(vpc_id, subnets, interface_service_names, gateway_service_names, route_table_id):
#Replace the aws-cli-profile-name with your profile name

    #if using cloudshell, comment out the below line
    boto3.setup_default_session(profile_name='aws-cli-profile-name')

    ec2_client = boto3.client('ec2')

    try:
        vpc_endpoint_ids_interface = []

        for service_name in interface_service_names:

            response = ec2_client.create_vpc_endpoint(
                VpcId=vpc_id,
                ServiceName=service_name,
                SubnetIds= subnets,
                VpcEndpointType='Interface'
            )
            vpc_endpoint_ids_interface.append(response['VpcEndpoint']['VpcEndpointId'])
            print(f"VPC Endpoint for {service_name} created with ID: {response['VpcEndpoint']['VpcEndpointId']}")

        print("Interface VPC Endpoints created successfully!")

        vpc_endpoint_ids_gateway = []

        for service_name in gateway_service_names:
            response = response = ec2_client.create_vpc_endpoint(
                VpcId=vpc_id,
                ServiceName=service_name,
                VpcEndpointType='Gateway',
                RouteTableIds= [route_table_id]
            )
            vpc_endpoint_id = response['VpcEndpoint']['VpcEndpointId']
            vpc_endpoint_ids_gateway.append(vpc_endpoint_id)
            print(f"VPC Endpoint for {service_name} created with ID: {vpc_endpoint_id}")

        print("Gateway VPC Endpoints Created Succesfully!")

        print("All VPC Endpoints created and associated with Route Table successfully!")     

        return vpc_endpoint_ids_interface, vpc_endpoint_ids_gateway
    
    except Exception as e:
        print("Error creating VPC endpoints:", str(e))
        return None

if __name__ == "__main__":
    # Replace these variables with your actual VPC ID and the desired regions
    vpc_id = 'vpc-id'
    subnets_id = ['subnet-id-A', 'subnet-id-B', 'subnet-id-C' ]
    console_region = 'console-region'
    route_table = 'route-table-id'
    
    #   OPTIONAL: Tightening Permissions #
        # You can remove fsx, elasticfilesystem, and ebs if you're not planning to scan those services
        # You can remove marketplace if you're using BYOL
        # You can remove Securityhub endpoint if not using Security Hub

    interface_services_to_create = [ 
                        f'com.amazonaws.{console_region}.s3', f'com.amazonaws.{console_region}.cloudformation',f'com.amazonaws.{console_region}.logs', 
                        f'com.amazonaws.{console_region}.ssm',f'com.amazonaws.{console_region}.application-autoscaling', f'com.amazonaws.{console_region}.ecs',
                        f'com.amazonaws.{console_region}.ecs-agent', f'com.amazonaws.{console_region}.kms', f'com.amazonaws.{console_region}.sts',  
                        f'com.amazonaws.{console_region}.ecr.dkr', f'com.amazonaws.{console_region}.autoscaling',f'com.amazonaws.{console_region}.ecr.api', 
                        f'com.amazonaws.{console_region}.sns', f'com.amazonaws.{console_region}.sqs', 
                        f'com.amazonaws.{console_region}.ec2', f'com.amazonaws.{console_region}.elasticloadbalancing',
                        f'com.amazonaws.{console_region}.monitoring', f'com.amazonaws.{console_region}.ebs',
                        f'com.amazonaws.{console_region}.appconfig', f'com.amazonaws.{console_region}.cognito-idp',
                        f'com.amazonaws.{console_region}.fsx',f'com.amazonaws.{console_region}.elasticfilesystem', 
                        f'com.amazonaws.{console_region}.securityhub', f'com.amazonaws.{console_region}.metering-marketplace']
    
    
    
    gateway_services_to_create = [f'com.amazonaws.{console_region}.s3', f'com.amazonaws.{console_region}.dynamodb']

    created_endpoint_ids = create_vpc_endpoints(vpc_id, subnets_id, interface_services_to_create, gateway_services_to_create, route_table)
```

&#x20;
{% endtab %}

{% tab title="Python - Agents VPC Endpoints Script" %}
Replace variables and awscli profile name

```python
import boto3

def create_vpc_endpoints(vpc_id, subnets, interface_service_names, gateway_service_names, route_table_id):
#Replace the aws-cli-profile-name with your profile name

    #if using cloudshell, comment out the below line
    boto3.setup_default_session(profile_name='aws-cli-profile-name')
    
    ec2_client = boto3.client('ec2')

    try:
        vpc_endpoint_ids_interface = []

        for service_name in interface_service_names:

            response = ec2_client.create_vpc_endpoint(
                VpcId=vpc_id,
                ServiceName=service_name,
                SubnetIds= subnets,
                VpcEndpointType='Interface'
            )
            vpc_endpoint_ids_interface.append(response['VpcEndpoint']['VpcEndpointId'])
            print(f"VPC Endpoint for {service_name} created with ID: {response['VpcEndpoint']['VpcEndpointId']}")

        print("Interface VPC Endpoints created successfully!")

        vpc_endpoint_ids_gateway = []

        for service_name in gateway_service_names:
            response = response = ec2_client.create_vpc_endpoint(
                VpcId=vpc_id,
                ServiceName=service_name,
                VpcEndpointType='Gateway',
                RouteTableIds= [route_table_id]
            )
            vpc_endpoint_id = response['VpcEndpoint']['VpcEndpointId']
            vpc_endpoint_ids_gateway.append(vpc_endpoint_id)
            print(f"VPC Endpoint for {service_name} created with ID: {vpc_endpoint_id}")

        print("Gateway VPC Endpoints Created Succesfully!")

        print("All VPC Endpoints created and associated with Route Table successfully!")     

        return vpc_endpoint_ids_interface, vpc_endpoint_ids_gateway
    
    except Exception as e:
        print("Error creating VPC endpoints:", str(e))
        return None

if __name__ == "__main__":
    # Replace these variables with your actual VPC ID and the desired regions
    vpc_id = 'vpc-id'
    subnets_id = ['subnet-id-A', 'subnet-id-B', 'subnet-id-C' ]
    agent_region = 'agent-region'
    route_table = 'route-table-id'
    console_region = 'console-region'

    #   OPTIONAL: Tightening Permissions #
        # You can remove fsx, elastifcilesystem, and ebs if you're not planning to scan those services
        # You can remove cognito-idp if not using api agent
        # You can remove Securityhub endpoint if not using Security Hub

    interface_services_to_create = [ 
                        f'com.amazonaws.{agent_region}.s3',f'com.amazonaws.{agent_region}.logs', 
                        f'com.amazonaws.{agent_region}.ssm',f'com.amazonaws.{agent_region}.application-autoscaling', f'com.amazonaws.{agent_region}.ecs',
                        f'com.amazonaws.{agent_region}.ecs-agent', f'com.amazonaws.{agent_region}.kms', f'com.amazonaws.{agent_region}.sts',  
                        f'com.amazonaws.{agent_region}.ecr.dkr', f'com.amazonaws.{agent_region}.autoscaling',f'com.amazonaws.{agent_region}.ecr.api', 
                        f'com.amazonaws.{agent_region}.sns', f'com.amazonaws.{agent_region}.sqs', f'com.amazonaws.{agent_region}.ec2',
                        f'com.amazonaws.{agent_region}.ebs', f'com.amazonaws.{console_region}.fsx',f'com.amazonaws.{console_region}.elasticfilesystem', 
                        f'com.amazonaws.{console_region}.appconfig', f'com.amazonaws.{agent_region}.securityhub', 
                        f'com.amazonaws.{console_region}.cognito-idp']

    gateway_services_to_create = [f'com.amazonaws.{agent_region}.s3', f'com.amazonaws.{agent_region}.dynamodb']

    created_endpoint_ids = create_vpc_endpoints(vpc_id, subnets_id, interface_services_to_create, gateway_services_to_create, route_table)
```

{% endtab %}
{% endtabs %}

## Using our Private Deployment Template

If you need a way to deploy privately but aren't sure which subnets to use from your current VPCs or which VPC endpoints to setup, you can use our private deployment CFT to create a new VPC with all of the resources (subnets, VPC endpoints, etc.) needed to deploy your Management Console and scanning agents in a fully private environment.

This template will first deploy the following networking pieces before deploying the software:

* A VPC and public + private subnets
* All necessary VPC endpoints in a single region
* An AWS network firewall
* An application load balancer that will sit in front of your management console. You will need a valid SSL certificate from AWS Certificate Manager to be able to deploy.

{% hint style="warning" %}
AWS Network Firewalls can be costly. If you are only performing testing make sure you don't forget about the deployment and properly tear it down.
{% endhint %}

Below is a screenshot of the parameters you can expect within the private deployment CloudFormation template.

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2FkzRMe65RxlCu84M8rzqO%2Fscreencapture-us-east-1-console-aws-amazon-cloudformation-home-2024-12-11-14_34_07.png?alt=media&#x26;token=20348c39-b9a2-4440-bffb-5cedd71c87d4" alt="" width="188"><figcaption><p>Select the image to expand it</p></figcaption></figure>

You can always find the latest version of our private deployment template [here](https://css-cft.s3.amazonaws.com/ConsoleCloudFormationTemplate-PrivateDeployment.yaml).

## API Endpoint

The API Endpoint is another Agent Service that allows for an [API Driven scan](https://help.cloudstoragesec.com/object-scanning#api-driven-scanning) of files and objects. It can be mixed into any of the deployment options above. It earns a special call out because it has its own Application Load Balancer deployed for and associated with it. So you can have a deployment that has an ALB fronting the Console and then another ALB fronting the API Endpoint. Like previously discussed load balancers, you can choose to make the ALB `internet-facing` or `internal`, it all depends on your needs.

{% hint style="info" %}
We are not showing a multi-region deployment below, but if your requirements dictate it, you can deploy as many API Endpoints as needed so scanning can be close to users/applications/data.
{% endhint %}

{% tabs %}
{% tab title="API Endpoint - Publicly Accessible" %}

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2FobURQzc4WHvoIhlgc1cL%2Fapi-public-annotated.png?alt=media&#x26;token=45deb511-8249-419b-ba73-60897e398928" alt=""><figcaption><p>Public API</p></figcaption></figure>

1. Users can configure their application to upload their file to an API endpoint that the Scanning Agent sits behind via an HTTPS request.
2. The request and file is processed through the Internet Gateway sitting at the entrance of the VPC where the API Agent resides.
3. The request and file reach the Application Load Balancer which resides in the public subnet.
4. The file included in the request is scanned with the API Agent and a verdict is rendered by the Agent.
5. Using the same channels, the Agent returns a JSON response via HTTPS with the decision on the file: Infected, Clean, etc.
6. (Optional) The API Agent can upload Clean files to the S3 bucket of your choice.
   {% endtab %}

{% tab title="API Endpoint - Privately Accessible" %}

<figure><img src="https://905555942-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlGcQw8I2CHyi1loKBlfi%2Fuploads%2FprJGYRnDuCNC9tIzpT9Y%2Fapi-private-annotated.png?alt=media&#x26;token=46a0ddad-4dae-401c-9661-76732a3d78cc" alt=""><figcaption><p>Private API</p></figcaption></figure>

1. The user must configure either AWS Direct Connect, a VPN, or a jumpbox to access the private subnet. Using a method of choice, the user uploads the file to an API endpoint that the Scanning Agent sits behind via an HTTPS request.
2. The request and file is processed through the Internet Gateway sitting at the entrance of the VPC where the API Agent resides.
3. The request and file reach the Application Load Balancer which resides in the private subnet.
4. The file included in the request is scanned with the API Agent and a verdict is rendered by the Agent.
5. Using the same channels, the Agent returns a JSON response via HTTPS with the decision on the file: Infected, Clean, etc.
6. (Optional) The API Agent can upload Clean files to the S3 bucket of your choice.
   {% endtab %}
   {% endtabs %}

Read more about our API Scanning [here](https://help.cloudstoragesec.com/how-it-works/object-scanning/api-driven-scanning).&#x20;


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.cloudstoragesec.com/how-it-works/deployment-details.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
