# TwinGate CDK Deploy

The convertiv-cdk package contains code to deploy the TwinGate vpn appliance
into an AWS account. Once Twingate is added to a VPC, you can define resources
present in that VPC. CNV users with twingate accounts can then gain access
to those resources by the dns name or ip address.

## Options

We provide two options for deploying the appliance - a package as part of
an existing stack (useful for long term applications, and CV internal apps)
or as a stand alone stack (useful for client apps, where we can just remove
the stack at the end to remove access).

- TwinGateService - Package
- TwinGateServiceStack - Stack

## General Prerequesits

### Create a Network and Connector

Before you deploy the appliance, you'll need to create a network and a
connector in TwinGate.

1. Log in to convertiv.twingate.com
2. Under Remote Networks click Add
3. Choose AWS and Type a name
4. Under connectors, click Add
5. Click Deploy Connector
6. Choose AWS ECS
7. Click Generate Tokens
8. Under Manage, click edit and name the connector something logical

### Create a secret in AWS

Both the stack and the package require three env vars -

- `ACCESS_TOKEN`
- `REFRESH_TOKEN`
- `TENENT_URL`

The access token and refresh token should never be disclosed, and should not
included in the repository. The easiest way to store these tokens is in a
manually created AWS secret store

1. Log into the AWS account
2. Go to Secret Manager
3. Create a secret
4. Store these two secrets in that value
5. Save and make note of the ARN provided

## Deploying the Stack (TwinGateServiceStack)

Deploy this if you want a standalone stack that you can spin up and down.
You can reuse the env vars and the App if you want, but this example assumes
that you are defining a new cdk project

### Properties
`secretARN` The stack expects a secretARN, and requires that the environment has a twingate
access token and refresh token. The stack will try to build that environment
from the secrets, and the custom env, and will fail to build if it can't
construct the project.

`assignPublicIp` Assign a public ip to the container.  This will default to false
and expect that the VPC has a routing from the private subnet to the egress.
If this isn't true, the container won't be able to find the internet and will
fail to boot.  If you want, you can set this to true so the container is in the
public subnet and uses the public subnet for egress.

`vpc`
In principle the vpc property is optional, though in practice that would be
weird. That would create a stand alone VPC, with nothing in it. When you terminate
this, the VPC would go with it. You wouldn't want, normally, to deploy this
stack into a AWS account without a vpc.

The vpc prop will accept either a vpc id or an IVPC object. This way if you
create a vpc in another stack, you can reference that vpc as an object.

`clusterARN`
The clusterArn prop is optional. Sometimes you may want to deploy the appliance
along side an existing fargate service, and sometimes you might want a stand
alone cluster. If you want a stand alone cluster, leave this property out.

`subnet1` The subnet to deploy the stack into.  WIll default to the public
subnet 
```
import {
    TwinGateServiceStack,
  } from "convertiv-cdk";
  const app = new App();
  const stack = new TwinGateServiceStack(app, 'client-name-cnv-vpn', {
    name: 'client-name-cnv-vpn', // How the stack and resources will be named in AWS
    env: 'production', // What environment should we use
    vpc: 'vpcId', // Optional, If not set, one will be created, if set, it can be a vpc id, or a IVPC object
    subnet1: '', // The subnet to attach to the stack.  Will default to the first private if assignPublicIp is false, and the first public if that is true.
    assignPublicIp: false, // Optional.  Will default to false.  If this is false, you must have an egress ip and a route table to route to egress or the container will not boot.
    tag: '1', The version of the twingate/connector to use. They recommend 1, but you can fix this to a minor version as needed
    clusterArn: 'clusterARN', // Optional, the ARN of the cluster that you want to boot the service into.  One will be created if not set.
    desired: 1, // Optional: How many tasks should be run (default: 1)
    cpu: 1, // Optional: How many CPUs should be used (default: 1)
    memory: 2, // Optional: How much memory (in gb) (default: 2)
    tenant_url: 'convertiv.twingate.com', // The tenent url provided
    twingateName: 'client-name', // The connector name
    secretsARN: 'secrets-arn', // The secret ARN you defined earlier
    customEnvironment: { // The env vars to pass to the task as key/value pairs
      TENANT_URL: "https://convertiv.twingate.com",
    },
    customEnvironmentSecrets: { // Key Value pairs to look up secret vars from the env
      ACCESS_TOKEN: "TWINGATE_ACCESS_TOKEN",
      REFRESH_TOKEN: "TWINGATE_REFRESH_TOKEN",
    },
  }, {
    env: {
      account: "11111111", // Account number
      region: "us-east-1", // Region
    },
    terminationProtection: true, // Termination protection
    description: // A description the vpn in the cloud formation interface.
      "cnv-vpn: Here's a description of our vpn",
    tags: {
      Application: "cnv-vpn", // the name of the app
      Environment: "production", // The environment
      Owner: "ops@convertiv.com", // Your Email
      // Other tags
    },
  });
}
```

## Deploying the package (TwinGateService)

Choose a package deploy for long term infrastructure, or if you want to
build a custom cdk stack with the twingate service attached.

The options are largely the same as the above with some notible differences

`vpc` is required, and must be a string

`subnet1` optional, defines what subnet id should be attached. T

`cluster` optional, to boot the service into an existing clusterArn

```
const service = new TwinGateService(appServiceStage, {
    desired: 1,
    min: 1,
    max: 1,
    cpu: 1024,
    memory: 2048,
    twingateName: "convertiv-motiv-vpn",
    name: "convertiv-vpn",
    vpc: appServiceStage.network.vpc.vpcId,
    assignPublicIp: false, 
    subnet1: appServiceStage.network.vpc.publicSubnets.pop()?.subnetId,
    cluster: appServiceStage.cluster.cluster,
    environment: {
      TENANT_URL: "https://convertiv.twingate.com",
      ACCESS_TOKEN: vpnSecret
        .secretValueFromJson("CNV_VPN_ACCESS_TOKEN")
        .toString(),
      REFRESH_TOKEN: vpnSecret
        .secretValueFromJson("CNV_VPN_REFRESH_TOKEN")
        .toString(),
    },
    securityGroups: [appServiceStage.webService?.serviceSecurityGroup],
    tag: "1.65.0",
  });
```

#