

End of support notice: On May 31, 2026, AWS will end support for AWS Panorama. After May 31, 2026, you will no longer be able to access the AWS Panorama console or AWS Panorama resources. For more information, see [AWS Panorama end of support](https://docs.aws.amazon.com/panorama/latest/dev/panorama-end-of-support.html). 

# The AWS Panorama API


You can use the AWS Panorama service's public API to automate device and application management workflows. With the AWS Command Line Interface or the AWS SDK, you can develop scripts or applications that manage resources and deployments. This guide's GitHub repository includes scripts that you can use as a starting point for your own code.

****
+ [aws-panorama-developer-guide/util-scripts](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/util-scripts)

**Topics**
+ [

# Automate device registration
](api-provision.md)
+ [

# Manage appliances with the AWS Panorama API
](api-appliance.md)
+ [

# Automate application deployment
](api-deploy.md)
+ [

# Manage applications with the AWS Panorama API
](api-applications.md)
+ [

# Using VPC endpoints
](api-endpoints.md)

# Automate device registration


To provision an appliance, use the [ProvisionDevice](https://docs.aws.amazon.com/panorama/latest/api/API_ProvisionDevice.html) API. The response includes a ZIP file with the device's configuration and temporary credentials. Decode the file and save it in an archive with the prefix `certificates-omni_`.

**Example [provision-device.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/util-scripts/provision-device.sh)**  

```
if [[ $# -eq 1 ]] ; then
    DEVICE_NAME=$1
else
    echo "Usage: ./provision-device.sh <device-name>"
    exit 1
fi
CERTIFICATE_BUNDLE=certificates-omni_${DEVICE_NAME}.zip
aws panorama provision-device --name ${DEVICE_NAME} --output text --query Certificates | base64 --decode > ${CERTIFICATE_BUNDLE}
echo "Created certificate bundle ${CERTIFICATE_BUNDLE}"
```

The credentials in the configuration archive expire after 5 minutes. Transfer the archive to your appliance with the included USB drive.

To register a camera, use the [CreateNodeFromTemplateJob](https://docs.aws.amazon.com/panorama/latest/api/API_CreateNodeFromTemplateJob.html) API. This API takes a map of template parameters for the camera's username, password, and URL. You can format this map as a JSON document by using Bash string manipulation.

**Example [register-camera.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/util-scripts/register-camera.sh)**  

```
if [[ $# -eq 3 ]] ; then
    NAME=$1
    USERNAME=$2
    URL=$3
else
    echo "Usage: ./register-camera.sh <stream-name> <username> <rtsp-url>"
    exit 1
fi
echo "Enter camera stream password: "
read PASSWORD
TEMPLATE='{"Username":"MY_USERNAME","Password":"MY_PASSWORD","StreamUrl": "MY_URL"}'
TEMPLATE=${TEMPLATE/MY_USERNAME/$USERNAME}
TEMPLATE=${TEMPLATE/MY_PASSWORD/$PASSWORD}
TEMPLATE=${TEMPLATE/MY_URL/$URL}
echo ${TEMPLATE}
JOB_ID=$(aws panorama create-node-from-template-job --template-type RTSP_CAMERA_STREAM --output-package-name ${NAME} --output-package-version "1.0" --node-name ${NAME} --template-parameters "${TEMPLATE}" --output text)
```

Alternatively, you can load the JSON configuration from a file.

```
--template-parameters file://camera-template.json
```

# Manage appliances with the AWS Panorama API
Manage appliance

You can automate appliance management tasks with the AWS Panorama API.

## View devices


To get a list of appliances with device IDs, use the [ListDevices](https://docs.aws.amazon.com/panorama/latest/api/API_ListDevices.html) API.

```
$ aws panorama list-devices
    "Devices": [
        {
            "DeviceId": "device-4tafxmplhtmzabv5lsacba4ere",
            "Name": "my-appliance",
            "CreatedTime": 1652409973.613,
            "ProvisioningStatus": "SUCCEEDED",
            "LastUpdatedTime": 1652410973.052,
            "LeaseExpirationTime": 1652842940.0
        }
    ]
}
```

To get more details about an appliance, use the [DescribeDevice](https://docs.aws.amazon.com/panorama/latest/api/API_DescribeDevice.html) API.

```
$ aws panorama describe-device --device-id device-4tafxmplhtmzabv5lsacba4ere
{
    "DeviceId": "device-4tafxmplhtmzabv5lsacba4ere",
    "Name": "my-appliance",
    "Arn": "arn:aws:panorama:us-west-2:123456789012:device/device-4tafxmplhtmzabv5lsacba4ere",
    "Type": "PANORAMA_APPLIANCE",
    "DeviceConnectionStatus": "ONLINE",
    "CreatedTime": 1648232043.421,
    "ProvisioningStatus": "SUCCEEDED",
    "LatestSoftware": "4.3.55",
    "CurrentSoftware": "4.3.45",
    "SerialNumber": "GFXMPL0013023708",
    "Tags": {},
    "CurrentNetworkingStatus": {
        "Ethernet0Status": {
            "IpAddress": "192.168.0.1/24",
            "ConnectionStatus": "CONNECTED",
            "HwAddress": "8C:XM:PL:60:C5:88"
        },
        "Ethernet1Status": {
            "IpAddress": "--",
            "ConnectionStatus": "NOT_CONNECTED",
            "HwAddress": "8C:XM:PL:60:C5:89"
        }
    },
    "LeaseExpirationTime": 1652746098.0
}
```

## Upgrade appliance software


If the `LatestSoftware` version is newer than the `CurrentSoftware`, you can upgrade the device. Use the [CreateJobForDevices](https://docs.aws.amazon.com/panorama/latest/api/API_CreateJobForDevices.html) API to create an over-the-air (OTA) update job.

```
$ aws panorama create-job-for-devices --device-ids device-4tafxmplhtmzabv5lsacba4ere \
  --device-job-config '{"OTAJobConfig": {"ImageVersion": "4.3.55"}}' --job-type OTA
{
    "Jobs": [
        {
            "JobId": "device-4tafxmplhtmzabv5lsacba4ere-0",
            "DeviceId": "device-4tafxmplhtmzabv5lsacba4ere"
        }
    ]
}
```

In a script, you can populate the image version field in the job configuration file with Bash string manipulation.

**Example [check-updates.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/util-scripts/check-updates.sh)**  

```
apply_update() {
    DEVICE_ID=$1
    NEW_VERSION=$2
    CONFIG='{"OTAJobConfig": {"ImageVersion": "NEW_VERSION"}}'
    CONFIG=${CONFIG/NEW_VERSION/$NEW_VERSION}
    aws panorama create-job-for-devices --device-ids ${DEVICE_ID} --device-job-config "${CONFIG}" --job-type OTA
}
```

The appliance downloads the specified software version and updates itself. Watch the update's progress with the [DescribeDeviceJob](https://docs.aws.amazon.com/panorama/latest/api/API_DescribeDeviceJob.html) API.

```
$ aws panorama describe-device-job --job-id device-4tafxmplhtmzabv5lsacba4ere-0
{
    "JobId": "device-4tafxmplhtmzabv5lsacba4ere-0",
    "DeviceId": "device-4tafxmplhtmzabv5lsacba4ere",
    "DeviceArn": "arn:aws:panorama:us-west-2:559823168634:device/device-4tafxmplhtmzabv5lsacba4ere",
    "DeviceName": "my-appliance",
    "DeviceType": "PANORAMA_APPLIANCE",
    "ImageVersion": "4.3.55",
    "Status": "REBOOTING",
    "CreatedTime": 1652410232.465
}
```

To get a list of all running jobs, use the [ListDevicesJobs](https://docs.aws.amazon.com/panorama/latest/api/API_ListDevicesJobs.html).

```
$ aws panorama list-devices-jobs
{
    "DeviceJobs": [
        {
            "DeviceName": "my-appliance",
            "DeviceId": "device-4tafxmplhtmzabv5lsacba4ere",
            "JobId": "device-4tafxmplhtmzabv5lsacba4ere-0",
            "CreatedTime": 1652410232.465
        }
    ]
}
```

For a sample script that checks for and applies updates, see [check-updates.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/util-scripts/check-updates.sh) in this guide's GitHub repository.

## Reboot appliances


To reboot an appliance, use the [CreateJobForDevices](https://docs.aws.amazon.com/panorama/latest/api/API_CreateJobForDevices.html) API.

```
$ aws panorama create-job-for-devices --device-ids device-4tafxmplhtmzabv5lsacba4ere --job-type REBOOT
{
    "Jobs": [
        {
            "JobId": "device-4tafxmplhtmzabv5lsacba4ere-0",
            "DeviceId": "device-4tafxmplhtmzabv5lsacba4ere"
        }
    ]
}
```

In a script, you can get a list of devices and choose one to reboot interactively.

**Example [reboot-device.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/util-scripts/reboot-device.sh) – usage**  

```
$ ./reboot-device.sh
Getting devices...
0: device-53amxmplyn3gmj72epzanacniy     my-se70-1
1: device-6talxmpl5mmik6qh5moba6jium     my-manh-24
Choose a device
1
Reboot device device-6talxmpl5mmik6qh5moba6jium? (y/n)y
{
    "Jobs": [
        {
            "DeviceId": "device-6talxmpl5mmik6qh5moba6jium",
            "JobId": "device-6talxmpl5mmik6qh5moba6jium-8"
        }
    ]
}
```

# Automate application deployment


To deploy an application, you use both the AWS Panorama Application CLI and AWS Command Line Interface. After building the application container, you upload it and other assets to an Amazon S3 access point. You then deploy the application with the [CreateApplicationInstance](https://docs.aws.amazon.com/panorama/latest/api/API_CreateApplicationInstance.html) API.

For more context and instructions for using the scripts shown, follow the instructions in the [sample application README](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/README.md).

**Topics**
+ [

## Build the container
](#api-deploy-build)
+ [

## Upload the container and register nodes
](#api-deploy-upload)
+ [

## Deploy the application
](#api-deploy-deploy)
+ [

## Monitor the deployment
](#api-deploy-monitor)

## Build the container


To build the application container, use the `build-container` command. This command builds a Docker container and saves it as a compressed file system in the `assets` folder.

**Example [3-build-container.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/3-build-container.sh)**  

```
CODE_PACKAGE=SAMPLE_CODE
ACCOUNT_ID=$(aws sts get-caller-identity --output text --query 'Account')
panorama-cli build-container --container-asset-name code_asset --package-path packages/${ACCOUNT_ID}-${CODE_PACKAGE}-1.0
```

You can also use command-line completion to fill in the path argument by typing part of the path, and then pressing TAB.

```
$ panorama-cli build-container --package-path packages/TAB
```

## Upload the container and register nodes


To upload the application, use the `package-application` command. This command uploads assets from the `assets` folder to an Amazon S3 access point that AWS Panorama manages.

**Example [4-package-app.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/4-package-app.sh)**  

```
panorama-cli package-application
```

 The AWS Panorama Application CLI uploads container and descriptor assets referenced by the package configuration (`package.json`) in each package, and registers the packages as nodes in AWS Panorama. You then refer to these nodes in your application manifest (`graph.json`) to deploy the application.

## Deploy the application


To deploy the application, you use the [CreateApplicationInstance](https://docs.aws.amazon.com/panorama/latest/api/API_CreateApplicationInstance.html) API. This action takes the following parameters, among others.

****
+ `ManifestPayload` – The application manifest (`graph.json`) that defines the application's nodes, packages, edges, and parameters.
+ `ManifestOverridesPayload` – A second manifest that overrides parameters in the first. The application manifest can be considered as a static resource in the application source, where the override manifest provides deploy-time settings that customize the deployment.
+ `DefaultRuntimeContextDevice` – The target device.
+ `RuntimeRoleArn` – The ARN of an IAM role that the application uses to access AWS services and resources.
+ `ApplicationInstanceIdToReplace` – The ID of an existing application instance to remove from the device.

The manifest and override payloads are JSON documents that must be provided as a string value nested inside of another document. To do this, the script loads the manifests from a file as a string and uses the [jq tool](https://stedolan.github.io/jq/) to construct the nested document.

**Example [5-deploy.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/5-deploy.sh) – compose manifests**  

```
GRAPH_PATH="graphs/my-app/graph.json"
OVERRIDE_PATH="graphs/my-app/override.json"
# application manifest
GRAPH=$(cat ${GRAPH_PATH} | tr -d '\n' | tr -d '[:blank:]')
MANIFEST="$(jq --arg value "${GRAPH}" '.PayloadData="\($value)"' <<< {})"
# manifest override
OVERRIDE=$(cat ${OVERRIDE_PATH} | tr -d '\n' | tr -d '[:blank:]')
MANIFEST_OVERRIDE="$(jq --arg value "${OVERRIDE}" '.PayloadData="\($value)"' <<< {})"
```

The deploy script uses the [ListDevices](https://docs.aws.amazon.com/panorama/latest/api/API_ListDevices.html) API to get a list of registered devices in the current Region, and saves the users choice to a local file for subsequent deployments.

**Example [5-deploy.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/5-deploy.sh) – find a device**  

```
    echo "Getting devices..."
    DEVICES=$(aws panorama list-devices)
    DEVICE_NAMES=($((echo ${DEVICES} | jq -r '.Devices |=sort_by(.LastUpdatedTime) | [.Devices[].Name] | @sh') | tr -d \'\"))
    DEVICE_IDS=($((echo ${DEVICES} | jq -r '.Devices |=sort_by(.LastUpdatedTime) | [.Devices[].DeviceId] | @sh') | tr -d \'\"))
    for (( c=0; c<${#DEVICE_NAMES[@]}; c++ ))
    do
        echo "${c}: ${DEVICE_IDS[${c}]}     ${DEVICE_NAMES[${c}]}"
    done
    echo "Choose a device"
    read D_INDEX
    echo "Deploying to device ${DEVICE_IDS[${D_INDEX}]}"
    echo -n ${DEVICE_IDS[${D_INDEX}]} > device-id.txt
    DEVICE_ID=$(cat device-id.txt)
```

The application role is created by another script ([1-create-role.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/1-create-role.sh)). The deploy script gets the ARN of this role from AWS CloudFormation. If the application is already deployed to the device, the script gets the ID of that application instance from a local file.

**Example [5-deploy.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/5-deploy.sh) – role ARN and replacement arguments**  

```
# application role
STACK_NAME=panorama-${NAME}
ROLE_ARN=$(aws cloudformation describe-stacks --stack-name panorama-${PWD##*/} --query 'Stacks[0].Outputs[?OutputKey==`roleArn`].OutputValue' --output text)
ROLE_ARG="--runtime-role-arn=${ROLE_ARN}"

# existing application instance id
if [ -f "application-id.txt" ]; then
    EXISTING_APPLICATION=$(cat application-id.txt)
    REPLACE_ARG="--application-instance-id-to-replace=${EXISTING_APPLICATION}"
    echo "Replacing application instance ${EXISTING_APPLICATION}"
fi
```

Finally, the script puts all of the pieces together to create an application instance and deploy the application to the device. The service responds with an instance ID which the script stores for later use.

**Example [5-deploy.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/5-deploy.sh) – deploy application**  

```
APPLICATION_ID=$(aws panorama create-application-instance ${REPLACE_ARG} --manifest-payload="${MANIFEST}" --default-runtime-context-device=${DEVICE_ID} --name=${NAME} --description="command-line deploy" --tags client=sample --manifest-overrides-payload="${MANIFEST_OVERRIDE}" ${ROLE_ARG} --output text)
echo "New application instance ${APPLICATION_ID}"
echo -n $APPLICATION_ID > application-id.txt
```

## Monitor the deployment


To monitor a deployment, use the [ListApplicationInstances](https://docs.aws.amazon.com/panorama/latest/api/API_ListApplicationInstances.html) API. The monitor script gets the device ID and application instance ID from files in the application directory and uses them to construct a CLI command. It then calls in a loop.

**Example [6-monitor-deployment.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/6-monitor-deployment.sh)**  

```
APPLICATION_ID=$(cat application-id.txt)
DEVICE_ID=$(cat device-id.txt)
QUERY="ApplicationInstances[?ApplicationInstanceId==\`APPLICATION_ID\`]"
QUERY=${QUERY/APPLICATION_ID/$APPLICATION_ID}
MONITOR_CMD="aws panorama list-application-instances --device-id ${DEVICE_ID} --query ${QUERY}"
MONITOR_CMD=${MONITOR_CMD/QUERY/$QUERY}
while true; do
    $MONITOR_CMD
    sleep 60
done
```

When the deployment completes, you can view logs by calling the Amazon CloudWatch Logs API. The view logs script uses the CloudWatch Logs `GetLogEvents` API.

**Example [view-logs.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/util-scripts/view-logs.sh)**  

```
GROUP="/aws/panorama/devices/MY_DEVICE_ID/applications/MY_APPLICATION_ID"
GROUP=${GROUP/MY_DEVICE_ID/$DEVICE_ID}
GROUP=${GROUP/MY_APPLICATION_ID/$APPLICATION_ID}
echo "Getting logs for group ${GROUP}."
#set -x
while true
do
    LOGS=$(aws logs get-log-events --log-group-name ${GROUP} --log-stream-name code_node --limit 150)
    readarray -t ENTRIES < <(echo $LOGS | jq -c '.events[].message')
    for ENTRY in "${ENTRIES[@]}"; do
        echo "$ENTRY" | tr -d \"
    done
    sleep 20
done
```

# Manage applications with the AWS Panorama API
Manage applications

You can monitor and manage applications with the AWS Panorama API.

## View applications


To get a list of applications running on an appliance, use the [ListApplicationInstances](https://docs.aws.amazon.com/panorama/latest/api/API_ListApplicationInstances.html) API.

```
$ aws panorama list-application-instances
    "ApplicationInstances": [
        {
            "Name": "aws-panorama-sample",
            "ApplicationInstanceId": "applicationInstance-ddaxxmpl2z7bg74ywutd7byxuq",
            "DefaultRuntimeContextDevice": "device-4tafxmplhtmzabv5lsacba4ere",
            "DefaultRuntimeContextDeviceName": "my-appliance",
            "Description": "command-line deploy",
            "Status": "DEPLOYMENT_SUCCEEDED",
            "HealthStatus": "RUNNING",
            "StatusDescription": "Application deployed successfully.",
            "CreatedTime": 1661902051.925,
            "Arn": "arn:aws:panorama:us-east-2:123456789012:applicationInstance/applicationInstance-ddaxxmpl2z7bg74ywutd7byxuq",
            "Tags": {
                "client": "sample"
            }
        },
    ]
}
```

To get more details about an application instance's nodes, use the [ListApplicationInstanceNodeInstances](https://docs.aws.amazon.com/panorama/latest/api/API_ListApplicationInstanceNodeInstances.html) API.

```
$ aws panorama list-application-instance-node-instances --application-instance-id applicationInstance-ddaxxmpl2z7bg74ywutd7byxuq
{
    "NodeInstances": [
        {
            "NodeInstanceId": "code_node",
            "NodeId": "SAMPLE_CODE-1.0-fd3dxmpl-interface",
            "PackageName": "SAMPLE_CODE",
            "PackageVersion": "1.0",
            "PackagePatchVersion": "fd3dxmpl2bdfa41e6fe1be290a79dd2c29cf014eadf7416d861ce7715ad5e8a8",
            "NodeName": "interface",
            "CurrentStatus": "RUNNING"
        },
        {
            "NodeInstanceId": "camera_node_override",
            "NodeId": "warehouse-floor-1.0-9eabxmpl-warehouse-floor",
            "PackageName": "warehouse-floor",
            "PackageVersion": "1.0",
            "PackagePatchVersion": "9eabxmple89f0f8b2f2852cca2a6e7971aa38f1629a210d069045e83697e42a7",
            "NodeName": "warehouse-floor",
            "CurrentStatus": "RUNNING"
        },
        {
            "NodeInstanceId": "output_node",
            "NodeId": "hdmi_data_sink-1.0-9c23xmpl-hdmi0",
            "PackageName": "hdmi_data_sink",
            "PackageVersion": "1.0",
            "PackagePatchVersion": "9c23xmplc4c98b92baea4af676c8b16063d17945a3f6bd8f83f4ff5aa0d0b394",
            "NodeName": "hdmi0",
            "CurrentStatus": "RUNNING"
        },
        {
            "NodeInstanceId": "model_node",
            "NodeId": "SQUEEZENET_PYTORCH-1.0-5d3cabda-interface",
            "PackageName": "SQUEEZENET_PYTORCH",
            "PackageVersion": "1.0",
            "PackagePatchVersion": "5d3cxmplb7113faa1d130f97f619655d8ca12787c751851a0e155e50eb5e3e96",
            "NodeName": "interface",
            "CurrentStatus": "RUNNING"
        }
    ]
}
```

## Manage camera streams


You can pause and resume camera stream nodes with the [SignalApplicationInstanceNodeInstances](https://docs.aws.amazon.com/panorama/latest/api/API_SignalApplicationInstanceNodeInstances.html) API.

```
$ aws panorama signal-application-instance-node-instances --application-instance-id applicationInstance-ddaxxmpl2z7bg74ywutd7byxuq \
        --node-signals '[{"NodeInstanceId": "camera_node_override", "Signal": "PAUSE"}]'
{
    "ApplicationInstanceId": "applicationInstance-ddaxxmpl2z7bg74ywutd7byxuq"
}
```

In a script, you can get a list of nodes and choose one to pause or resume interactively.

**Example [pause-camera.sh](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/util-scripts/pause-camera.sh) – usage**  

```
my-app$ ./pause-camera.sh

Getting nodes...
0: SAMPLE_CODE              RUNNING
1: warehouse-floor          RUNNING
2: hdmi_data_sink           RUNNING
3: entrance-north           PAUSED
4: SQUEEZENET_PYTORCH       RUNNING
Choose a node
1
Signalling node warehouse-floor
+ aws panorama signal-application-instance-node-instances --application-instance-id applicationInstance-r3a7xmplcbmpjqeds7vj4b6pjy --node-signals '[{"NodeInstanceId": "warehouse-floor", "Signal": "PAUSE"}]'
{
    "ApplicationInstanceId": "applicationInstance-r3a7xmplcbmpjqeds7vj4b6pjy"
}
```

By pausing and resuming camera nodes, you can cycle through a larger number of camera streams than can be processed simultaneously. To do this, map multiple camera streams to the same input node in your override manifest.

In the following example, the override manifest maps two camera streams, `warehouse-floor` and `entrance-north` to the same input node (`camera_node`). The `warehouse-floor` stream is active when the application starts and the `entrance-north` node waits for a signal to turn on.

**Example [override-multicam.json](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/sample-apps/aws-panorama-sample/graphs/my-app/override-multicam.json)**  

```
    "nodeGraphOverrides": {
        "nodes": [
            {
                "name": "warehouse-floor",
                "interface": "123456789012::warehouse-floor.warehouse-floor",
                "launch": "onAppStart"
            },
            {
                "name": "entrance-north",
                "interface": "123456789012::entrance-north.entrance-north",
                "launch": "onSignal"
            },
        ...
        "packages": [
            {
                "name": "123456789012::warehouse-floor",
                "version": "1.0"
            },
            {
                "name": "123456789012::entrance-north",
                "version": "1.0"
            }
        ],
        "nodeOverrides": [
            {
                "replace": "camera_node",
                "with": [
                    {
                        "name": "warehouse-floor"
                    },
                    {
                        "name": "entrance-north"
                    }
                ]
            }
```

For details on deploying with the API, see [Automate application deployment](api-deploy.md).

# Using VPC endpoints


If you work in a VPC without internet access, you can create a [VPC endpoint](#services-vpc-interface) for use with AWS Panorama. A VPC endpoint lets clients running in a private subnet connect to an AWS service without an internet connection.

For details on ports and endpoints used by the AWS Panorama Appliance, see [Connecting the AWS Panorama Appliance to your network](appliance-network.md).

**Topics**
+ [

## Creating a VPC endpoint
](#services-vpc-interface)
+ [

## Connecting an appliance to a private subnet
](#services-vpc-appliance)
+ [

## Sample AWS CloudFormation templates
](#services-vpc-templates)

## Creating a VPC endpoint


To establish a private connection between your VPC and AWS Panorama, create a *VPC endpoint*. A VPC endpoint is not required to use AWS Panorama. You only need to create a VPC endpoint if you work in a VPC without internet access. When the AWS CLI or SDK attempts to connect to AWS Panorama, the traffic is routed through the VPC endpoint.

[Create a VPC endpoint](https://console.aws.amazon.com//vpc/home#CreateVpcEndpoint:) for AWS Panorama using the following settings:
+ **Service name** – **com.amazonaws.*us-west-2*.panorama**
+ **Type** – **Interface**

A VPC endpoint uses the service's DNS name to get traffic from AWS SDK clients without any additional configuration. For more information about using VPC endpoints, see [Interface VPC endpoints](https://docs.aws.amazon.com/vpc/latest/userguide/vpce-interface.html) in the *Amazon VPC User Guide*.

## Connecting an appliance to a private subnet


The AWS Panorama Appliance can connect to AWS over a private VPN connection with AWS Site-to-Site VPN or AWS Direct Connect. With these services, you can create a private subnet that extends to your data center. The appliance connects to the private subnet and accesses AWS services through VPC endpoints.

Site-to-Site VPN and Direct Connect are services for connecting your data center to Amazon VPC securely. With Site-to-Site VPN, you can use commercially available network devices to connect. Direct Connect uses an AWS device to connect.

****
+ **Site-to-Site VPN** – [What is AWS Site-to-Site VPN?](https://docs.aws.amazon.com/vpn/latest/s2svpn/)
+ **Direct Connect** – [What is AWS Direct Connect?](https://docs.aws.amazon.com/directconnect/latest/UserGuide/)

After you've connected your local network to a private subnet in a VPC, create VPC endpoints for the following services.

****
+ **Amazon Simple Storage Service** – [AWS PrivateLink for Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/privatelink-interface-endpoints.html)
+ **AWS IoT Core** – [Using AWS IoT Core with interface VPC endpoints](https://docs.aws.amazon.com/iot/latest/developerguide/IoTCore-VPC.html) (data plane and credential provider)
+ **Amazon Elastic Container Registry** – [Amazon Elastic Container Registry interface VPC endpoints](https://docs.aws.amazon.com/AmazonECR/latest/userguide/vpc-endpoints.html)
+ **Amazon CloudWatch** – [Using CloudWatch with interface VPC endpoints ](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-and-interface-VPC.html)
+ **Amazon CloudWatch Logs** – [Using CloudWatch Logs with interface VPC endpoints](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/cloudwatch-logs-and-interface-VPC.html)

The appliance does not need connectivity to the AWS Panorama service. It communicates with AWS Panorama through a messaging channel in AWS IoT.

In addition to VPC endpoints, Amazon S3 and AWS IoT require the use of Amazon Route 53 private hosted zones. The private hosted zone routes traffic from subdomains, including subdomains for Amazon S3 access points and MQTT topics, to the correct VPC endpoint. For information on private hosted zones, see [Working with private hosted zones](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-private.html) in the Amazon Route 53 Developer Guide.

For a sample VPC configuration with VPC endpoints and private hosted zones, see [Sample AWS CloudFormation templates](#services-vpc-templates).

## Sample AWS CloudFormation templates


The GitHub repository for this guide provides AWS CloudFormation templates that you can use to create resources for use with AWS Panorama. The templates create a VPC with two private subnets, a public subnet, and a VPC endpoint. You can use the private subnets in the VPC to host resources that are isolated from the internet. Resources in the public subnet can communicate with the private resources, but the private resources can't be accessed from the internet.

**Example [vpc-endpoint.yml](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/cloudformation-templates/vpc-endpoint.yml) – Private subnets**  

```
AWSTemplateFormatVersion: 2010-09-09
Resources:
  vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 172.31.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Ref AWS::StackName
  privateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref vpc
      AvailabilityZone:
        Fn::Select:
         - 0
         - Fn::GetAZs: ""
      CidrBlock: 172.31.3.0/24
      MapPublicIpOnLaunch: false
      Tags:
        - Key: Name
          Value: !Sub  ${AWS::StackName}-subnet-a
  ...
```

The `vpc-endpoint.yml` template shows how to create a VPC endpoint for AWS Panorama. You can use this endpoint to manage AWS Panorama resources with the AWS SDK or AWS CLI.

**Example [vpc-endpoint.yml](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/cloudformation-templates/vpc-endpoint.yml) – VPC endpoint**  

```
  panoramaEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub com.amazonaws.${AWS::Region}.panorama
      VpcId: !Ref vpc
      VpcEndpointType: Interface
      SecurityGroupIds:
      - !GetAtt vpc.DefaultSecurityGroup
      PrivateDnsEnabled: true
      SubnetIds:
      - !Ref privateSubnetA
      - !Ref privateSubnetB
      PolicyDocument:
        Version: 2012-10-17		 	 	 
        Statement:
        - Effect: Allow
          Principal: "*"
          Action:
            - "panorama:*"
          Resource:
            - "*"
```

The `PolicyDocument` is a resource-based permissions policy that defines the API calls that can be made with the endpoint. You can modify the policy to restrict the actions and resources that can be accessed through the endpoint. For more information, see [Controlling access to services with VPC endpoints](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-endpoints-access.html) in the *Amazon VPC User Guide*. 

The `vpc-appliance.yml` template shows how to create VPC endpoints and private hosted zones for services used by the AWS Panorama Appliance.

**Example [vpc-appliance.yml](https://github.com/awsdocs/aws-panorama-developer-guide/blob/main/cloudformation-templates/vpc-appliance.yml) – Amazon S3 access point endpoint with private hosted zone**  

```
  s3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcId: !Ref vpc
      VpcEndpointType: Interface
      SecurityGroupIds:
      - !GetAtt vpc.DefaultSecurityGroup
      PrivateDnsEnabled: false
      SubnetIds:
      - !Ref privateSubnetA
      - !Ref privateSubnetB
...
  s3apHostedZone:
    Type: AWS::Route53::HostedZone
    Properties:
      Name: !Sub s3-accesspoint.${AWS::Region}.amazonaws.com
      VPCs: 
        - VPCId: !Ref vpc
          VPCRegion: !Ref AWS::Region
  s3apRecords:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId: !Ref s3apHostedZone
      Name: !Sub "*.s3-accesspoint.${AWS::Region}.amazonaws.com"
      Type: CNAME
      TTL: 600
      # first DNS entry, split on :, second value
      ResourceRecords: 
      - !Select [1, !Split [":", !Select [0, !GetAtt s3Endpoint.DnsEntries ] ] ]
```

The sample templates demonstrate the creation of Amazon VPC and Route 53 resources with a sample VPC. You can adapt these for your use case by removing the VPC resources and replacing the references to subnet, security group, and VPC IDs with the IDs of your resources.