Skip to content

Portward on AWS

For the person who runs AWS at your company. About 25 minutes, all in your own account, and nobody from Portward is involved. At the end, your team asks Claude or ChatGPT about company data through a gateway in your AWS account. People sign in with your company directory. The gateway swaps the values you mark as sensitive for tokens before the AI sees them, and records every answer in your account. Portward (the company) never receives your data.

One CloudFormation stack creates everything: the gateway as one ECS Fargate task, its records on encrypted EFS (backed up daily), its keys in Secrets Manager, its logs in CloudWatch. With the relay, AWS bills about $20 a month for it (Costs).

Claude / ChatGPT
│ HTTPS
▼
relay.portward.ai, which passes
TLS through and can't read it,
or with your own domain, your
load balancer (ACM certificate)
│
▼
your Fargate task
│
▼
your databases
  • An AWS account and a VPC that can reach your databases, with two subnets in different zones: public subnets, or private ones with a NAT gateway. The default VPC is fine to start.
  • Your company directory (Microsoft Entra, Okta, Google Workspace or any OpenID Connect directory), where you register one app for the gateway (step 2).
  • The address. Either:
    • relay (the default, cheapest): https://<name>.gw.portward.ai. The gateway only connects out. Nothing opens inbound and there is no load balancer. Caddy, in your task, gets the HTTPS certificate and keeps it in your account. The relay forwards encrypted traffic by name and can’t read it (what the relay sees). Signup picks the name from your email’s domain, and it is part of your license key.
    • domain: your own address, such as portward.yourcompany.com, on a load balancer with an ACM certificate. If you give the Route 53 zone, the stack makes the certificate and the address record. Or bring a certificate and point the address at the stack’s LoadBalancerDNS output yourself.
  • Read-only logins for the databases you’ll connect (later, from Claude or ChatGPT). Portward refuses a login that can write.

With the relay, it is https://<name>.gw.portward.ai, as the key page shows it. <name> is always the part of your license key between pwlic_ and the next _. With your own domain, it is the address you chose, such as https://portward.yourcompany.com. The rest of this guide calls it <address>.

2. Register the app in your directory (10 minutes)

Section titled “2. Register the app in your directory (10 minutes)”

Register one app with the redirect address <address>/auth/callback. Sign-in setup has the steps for Entra, Okta and Google. Keep its issuer, client id and client secret, and decide which directory group manages Portward (admins) and which may ask questions (users). Okta: also note the extra scope groups.

3. Create the stack (5 minutes, then about 5 minutes of AWS work)

Section titled “3. Create the stack (5 minutes, then about 5 minutes of AWS work)”

Press Deploy to AWS (also on the page that showed your license key). The CloudFormation console opens in your account at Quick create stack. Portward’s template is loaded and the stack is named portward. It opens in US East (Ohio), us-east-2. To use another region, change it at the top right. Nothing is created until you press Create stack. You can also choose Create stack and give the template URL https://portward-launch.s3.us-east-2.amazonaws.com/templates/1.1.1/aws/portward-ecs.yaml. Then check the region at the top right and name the stack, for example portward. The form is the same either way. Use this route too if you no longer have the key page: the key tells you the address (step 1).

The form groups its fields under six headings: “1. Your Portward license, and how Claude and ChatGPT reach the gateway” (License key to Route 53 zone), “2. Sign-in: the app you registered in your directory” (Directory sign-in address to Other users), “3. Network” (VPC to Database hosts), “4. Alerts”, “5. Restore from a backup” and “6. Images”. Fill in, in the form’s order:

ParameterWhat to put
License keyFrom the key page (Get started, step 2, pwlic_…). Paste it here. The stack stores it in Secrets Manager. It is never part of the link. The gateway uses it to download its image and to connect to the relay. The part between pwlic_ and the next _ is the name in your gateway’s address, the one the key page shows.
Addressrelay or domain, the two choices in its list
Your domaindomain only: the address, such as portward.yourcompany.com
Certificate (optional)domain only: an ACM certificate for that address
Route 53 zone (optional)domain only: the zone the stack makes the certificate and the address record in
Directory sign-in address (issuer)The issuer, exactly as your directory states it (Entra: https://login.microsoftonline.com/<tenant id>/v2.0)
App client idFrom step 2
App client secretFrom step 2. The secret goes straight into Secrets Manager and is never shown again.
Extra scopesOkta: groups. Others: empty.
Admin groupsComma-separated, as your directory sends them: Entra sends group Object IDs, Okta and others send names. Names may contain spaces. Put no space after a comma, as in Portward admins,Portward ops, or the form refuses the value.
User groupsThe groups whose members may ask questions, written the same way. While this and Other users are empty, only admins can ask. Empty is fine for a first answer by an admin.
Admins by sign-in idFor directories without groups (Google): the admins’ sign-in ids or verified emails, comma-separated, with no space after the commas
Other usersFor directories without groups: sign-in ids, verified emails, or @yourcompany.com for everyone at your domain
VPCThe VPC your databases are in, or one peered with it. For RDS, the instance’s Connectivity & security tab names its VPC.
SubnetsTwo subnets in different zones
Public IPENABLED for public subnets, DISABLED behind a NAT gateway
Database hostsThe database hosts admins may connect, such as db.internal.yourcompany.com,*.corp.yourcompany.com. Empty is fine to start. If you already know the host, enter it now: each later change is an Update stack that restarts the gateway.
Alert emailOptional: an address (a person or a team list) emailed when an update fails or the gateway stops running. AWS sends a confirmation email first; alerts start once it’s confirmed. Empty means nobody is emailed.
Restored file systemLeave empty for a new gateway. Use it only to start the stack from a backup: Update and back up.
Key of the backed-up stackLeave empty for a new gateway, as above.
Gateway imageLeave as it is. It names one release by version and digest (gateway:<version>@sha256:<digest>), so a restart or a redeploy runs the same image even if a tag moves.
Certificate image (relay) / Relay client image (relay)Leave as they are.

Tick “I acknowledge that AWS CloudFormation might create IAM resources.”, then Create stack. If someone else creates the stack, share the license key and the app’s client secret with them through your password manager, never in chat or email. To create the stack from a terminal instead, keep the secrets in files so they aren’t typed on the command line:

Terminal window
aws cloudformation create-stack --stack-name portward \
--template-url https://portward-launch.s3.us-east-2.amazonaws.com/templates/1.1.1/aws/portward-ecs.yaml \
--capabilities CAPABILITY_IAM --parameters file://portward-parameters.json # parameter list as in the table

The template is larger than the 51,200 bytes CloudFormation takes from a local file, so pass its address with --template-url. To edit the template first, upload your copy to an S3 bucket and pass that address.

When the stack shows CREATE_COMPLETE, its Outputs tab lists the addresses. Then:

  • <address>/health answers {"ok": true, ...}. In relay mode the stack only completes once the address serves its certificate.
  • Add the AdminConnector output in Claude or ChatGPT as a custom connector (Get started, step 7) and sign in with your directory account. Members of the admin groups, and the people in Admins by sign-in id, are admins.
  • If you’re refused, the Logs output (CloudWatch) names who signed in and the groups your directory sent: fix the group names in the stack’s parameters (Update stack, keep the template, change the value).

5. Connect your data and give your team access

Section titled “5. Connect your data and give your team access”

Each change below is an Update stack with the same template: change the parameter and keep the rest. Each update replaces the gateway’s task. ECS stops the old task before it starts the new one, so the address doesn’t answer until the new task is ready, about 2 to 3 minutes. In our test, an update of Database hosts took about 7 minutes from Update stack to UPDATE_COMPLETE. Make the changes in one update when you can.

  1. Add each database’s host to Database hosts. Object stores, Microsoft 365 and Google Drive don’t use this list.
  2. From the admin connector, set up the connection and choose what the AI may see: Get started, step 8.
  3. Put the groups whose members may ask questions in User groups. For a directory without groups, such as Google, use Other users: sign-in ids, verified emails, or @yourcompany.com for everyone at your domain. While both are empty, only admins can ask.
  4. Each of them adds the DataConnector output in Claude or ChatGPT: Get started, step 9.
ResourceWhy
ECS cluster, service, task (Fargate, ARM64, 0.5 vCPU, 1 GB)The gateway. One task, because only one gateway may write to the records at a time. relay mode adds two small containers to the same task: Caddy (gets and renews the HTTPS certificate; TLS ends here, in your account) and frpc (the outbound connection to the relay).
Execution roleLets ECS start the task. It may read the stack’s three secrets (only those), write to the stack’s log group (only that), and pull the gateway image from Portward’s registry with the license key. With an ECR image, such as the AWS Marketplace listing’s, it may pull from that registry only. ecr:GetAuthorizationToken is account-wide by AWS’s design; it grants no image by itself.
Task roleThe running gateway’s only AWS permission: mount and write its own records file system, through its own access points, never as root. It can’t read your other AWS resources. The gateway reads your data with the read-only logins you give it, and needs no AWS permission for that. Every container in the gateway’s task (Caddy and frpc too, in relay mode) has this role, so no container in the task can do more than this.
Secrets Manager: Key64 random characters generated in your account. It opens the saved connections and signs the access the gateway gives Claude and ChatGPT after sign-in. Kept if the stack is deleted.
Secrets Manager: DirectorySecret and LicenseSecretThe app’s client secret and the license key, as you entered them.
EFS file system (encrypted at rest with the AWS-managed key, TLS in transit enforced by its policy)The records: answer records, reveals (each Show of a hidden value), setup and governance changes, and the encrypted connection list. relay mode also keeps the certificate here. Kept if the stack is deleted. A file system restored from a backup gets the same policy and daily backups from the stack, and the stack refuses a restored one that isn’t encrypted.
Restore only: Lambda function RestoredStorageCheck and its roleRuns when the stack is pointed at a restored file system, before anything mounts it: puts the TLS-only policy and daily backups on it, or fails the create or update if it isn’t encrypted. Its role may do only that, on that file system only.
Restore only: restore task (task definition portward-<stack>-restore), its role RestoreRole and the access point RestoreAccessA one-off task, separate from the gateway’s, that moves the restored files into place and stops. AWS Backup puts restored files in a folder at the file system’s root that only root may change. So this task’s role may act as root on that file system, through RestoreAccess only. No other role has root there, and no container of the gateway’s task has this role. The role and access point stay with the stack while Restored file system is set, unused between runs.
Restore only: Lambda function RestoreRun and its roleRuns the restore task once the file system’s mount targets exist and waits for it, before the gateway starts. If the move fails, the create or update fails and the gateway stays where it was. It runs the task again only when an update changes Restored file system or the network settings. The task then finds the records in place and does nothing. Its role may only run that task in the stack’s cluster, check on it and stop it.
AWS Backup (the EFS automatic backup plan)A daily backup of the file system (05:00 UTC), kept 35 days, in the vault aws/efs/automatic-backup-vault.
Security groupsrelay: nothing may connect in; the task connects out (to your directory, the relay, the image registry and your databases). domain: only the load balancer reaches the task on 8765; the load balancer takes 443 (and 80, redirected to 443) from the internet, because Claude and ChatGPT connect from their own servers. EFS takes NFS only from the task.
CloudWatch alarm (about $0.10/month)Goes off when no gateway task has run for 5 minutes (the AWS/ECS metric LiveTaskCount, which ECS sends only while a task runs).
With an alert email: SNS topic, its policy, and an EventBridge ruleThe rule matches ECS’s SERVICE_DEPLOYMENT_FAILED event for this stack’s service; the rule and the alarm are the only senders the topic accepts. The topic is in the AlertTopic output if you want to add subscribers.
CloudWatch log group (90 days)Gateway, Caddy and relay logs. They name people by sign-in id and never contain row values.
domain only: load balancer, listeners, target group, and optionally ACM certificate and Route 53 recordYour own address, TLS 1.2/1.3 at the load balancer.
  • Your databases stay where they are. The gateway reads them with the read-only logins you give it.
  • Records and saved connections are on the stack’s EFS file system, encrypted at rest. Saved connection passwords are also encrypted with the gateway key.
  • Keys and secrets are in Secrets Manager in your account.
  • Portward never receives your data. With the relay, your encrypted traffic passes through Portward’s relay, which never has the key.
  • Update: update the stack with the new template: Update and back up.
  • Change who gets in: update the stack’s group parameters. The gateway also asks your directory again at least every hour, so someone disabled there loses access within the hour.
  • Rotate the directory secret before it expires: make a new one in your directory, then Update stack with it (or put it in the DirectorySecret secret and redeploy the service: aws ecs update-service --force-new-deployment).
  • The gateway key can’t be rotated, because it opens the saved connections. If you think it leaked, make a new stack and set the connections up again.
  • Health: to check the gateway yourself, open <address>/ready in a browser. doctor doesn’t run on AWS, and nothing on AWS checks your data sources. A database that stops answering shows up as a failing question. ECS marks the task healthy when /ready/release passes. It checks that the settings load, that this release can use the records file and has finished updating it, that the license key has the right form, and that the gateway is the image’s version. ECS replaces a task that fails it. In relay mode the address must also serve a valid certificate. In domain mode the load balancer checks /ready/release too.
  • What /ready/release leaves out: two checks of the records file that a new task or an earlier release can’t fix. One finds a log row that was edited, deleted or reordered. The other finds a saved connection the gateway key no longer opens. The gateway keeps running with either, so the gateway’s console stays up. A broken log shows on the console’s Overview as Logs need attention. The full /ready checks both. It is the image’s own Docker health check, and portward update uses it on a VM.
  • Alarm: the CloudWatch alarm counts no data as down. With an alert email, it emails you when it goes off and again when the gateway is back.
  • Back up and restore: the daily backup is on (AWS Backup → Backup vaults → aws/efs/automatic-backup-vault). To go back to one, see Update and back up. Keep the Key secret: without it, saved connections can’t be opened.
  • Quotas: one Fargate task, one EFS file system, three secrets; within every account’s default quotas.
relaydomain
Fargate, 0.5 vCPU + 1 GB ARM64, all month~$14~$14
Public IPv4 address for the task~$3.60~$3.60
Load balancer (and its two public addresses)none~$24, more with heavy traffic
Secrets Manager (3 secrets)$1.20$1.20
EFS (records are small), backups, logsunder $1under $1
Totalabout $20about $43

Data out to Claude and ChatGPT is billed as normal AWS data transfer (answers are small). Portward bills its own price separately.

Delete the stack. The Key secret and the EFS file system are kept on purpose (your records). To remove them too: delete the file system (EFS console) and the secret (Secrets Manager, Delete with no recovery window). AWS keeps the file system’s daily backups in aws/efs/automatic-backup-vault and deletes each one when it is 35 days old. AWS sets that vault’s access policy to refuse deletes. To delete the backups sooner, edit the policy first (AWS Backup → Backup vaults → aws/efs/automatic-backup-vault → Access policy). If the first create fails and rolls back, CloudFormation deletes the secret and the file system, and the stack itself stays with the status ROLLBACK_COMPLETE. Delete it before you try again with the same stack name. A file system restored from a backup was never part of the stack, so it is kept either way. One failed create leaves more behind. If you give the same subnet twice, which the CLI allows and the console doesn’t, EFS leaves a network interface in the stack’s storage security group, and the stack can’t finish deleting. Delete the stack again and choose to keep StorageSecurityGroup and TaskSecurityGroup. The interface and groups cost nothing. Once EFS removes the interface, delete the two groups.

You seeFix
The stack fails at the ServiceThe task couldn’t start: the stack’s Logs output, or ECS → the cluster → stopped tasks → Stopped reason. Often the subnets can’t reach the internet (public IP DISABLED without a NAT gateway).
<address> doesn’t answer (relay)The relay log stream (relay/...) says whether the relay accepted the license key. If the key is wrong, update the stack with the right one.
The stack fails at the Service, the gateway log looks fine (relay)Caddy got no certificate, and the https/... log stream says why. If it names a rate limit, that is Let’s Encrypt’s: 5 certificates for the same address every 7 days. Each new stack asks for a new one. The message says when you can try again.
Sign-in shows an error at your directoryThe app’s redirect address isn’t exactly <address>/auth/callback, or the client id is wrong.
Signed in, but refusedThe log names the groups your directory sent: fix Admin groups or User groups (Entra: Object IDs, not names; Okta: the scope groups and the groups claim, Sign-in setup).
The stack fails at RestoredStorageIts status reason says why: the file system “isn’t encrypted” (restore the recovery point again with Enable encryption), or no file system has that id in this account and region.
The stack fails at RestoredRecordsIts status reason gives the restore task’s exit code or what ECS said. The restore/... log stream says why: no Portward records on that file system (check the id), or more than one restore on it. Restore again into a new file system. If ECS couldn’t start the task three times (the image or the file system unreachable), see the first row.
A question about a database that worked before fails with “query failed: …”The gateway can’t reach it any more. Check that the database is running and that its security group still allows its port from the stack’s TaskSecurityGroup. Troubleshooting
The console’s Overview says Logs need attentionA row in the records file on EFS was edited, deleted or reordered since it was written. The gateway keeps running and answering. Restore an earlier backup into a new file system (Update and back up, Restore, steps 1 and 2) to compare, and check who can write to the EFS file system.