terraform/aws: add aws-app-connector-s3-privatelink - #51
Draft
maxiscoding28 wants to merge 6 commits into
Draft
Conversation
Route one specific S3 bucket privately through a Tailscale app connector
while all other buckets and web traffic continue to egress publicly.
An app connector pointed at a public S3 endpoint advertises whatever that
endpoint resolves to. S3 regional endpoints are large shared address pools
that rotate, so the advertised route set grows without bound. This example
gives the bucket a stable private address with an S3 interface VPC endpoint
first, then advertises that one address, so the route set is a fixed pair.
Three pieces have to line up:
1. The interface endpoint, with private DNS and
private_dns_only_for_inbound_resolver_endpoint = false, gives the
bucket a stable ENI address inside the VPC.
2. A split DNS entry on the exact bucket FQDN sends only that one name to
the VPC resolver. Sibling buckets do not match and stay public.
3. The connector advertises the VPC resolver and the endpoint ENI, and
SNATs both so they arrive as ordinary in-VPC traffic.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Match the mock example in CONTRIBUTING.md more closely. Cut comments from 51 lines to 26, in line with the other AWS examples. Move the subnet CIDR into locals and use the same local names as the mock (vpc_cidr_block, instance_subnet_id, instance_security_group_ids). Add the missing Name tag on the S3 object and rename resources to "main". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Tailscale provider has no app connector resource, so that stanza has to be added to the policy file by hand. Add a next_step_app_connector_policy output that prints it with the bucket domain and advertised routes filled in, ready to paste. Say plainly in the README why this step is manual. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The connector was passing both --advertise-connector and --advertise-routes. The second flag is not needed. App connector routes belong in the "routes" field of the app connector definition, where they are implicitly approved and need no autoApprovers entry. Move the routes into the stanza the output prints and drop the autoApprovers block from the README, which is no longer required. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The policy example mixed a prerequisite with a post-apply step. The tag owners have to exist before apply or key creation fails, while the app connector definition needs values the apply produces. Split the section into "before you apply" and "after you apply", and say in the deploy steps that the tag owners come first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
No other example prints instructions as an output. The README already shows the stanza, and s3_domain and s3_advertised_routes carry the two values that need filling in, so point at those instead. Also note that the VPC resolver address is derived from vpc_cidr_block, which matters when swapping in your own VPC. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed in #52.
What it does
Adds
terraform/aws/aws-app-connector-s3-privatelink/. Four files, 436 lines.The example routes traffic for one S3 bucket over a private path. Every other bucket, and all other traffic, keeps egressing publicly.
Why it is worth an example
Pointing an app connector at a public S3 endpoint does not work well. S3 regional endpoints resolve to a large pool of addresses that rotates. The connector keeps discovering new addresses, so the route set grows and never settles.
The fix is to give the bucket a stable private address first, then advertise that. Three pieces have to line up:
private_dns_only_for_inbound_resolver_endpoint = false. Resolving the bucket domain inside the VPC now returns the endpoint ENI.Checks
All three jobs from
terraform-examples.yml, run against a clean clone:tflint --chdir=terraform --recursivecheck-terraform-fmt.shcheck-variables-tailscale-install-scripts.shterraform validateApplied end to end in a sandbox account (us-west-2) and verified:
autoApproversentry, confirming policy-file routes are implicitly approvedStyle guide
localsblock at the top ofmain.tfwith every customizable valueexample-${basename(path.cwd)}prefix,Nametag on every resource that takes tagsvpc_cidr_block,instance_subnet_id,instance_security_group_idsinternal-modules/aws-vpcandinternal-modules/aws-ec2-instance, both removableterraform fmtclean,#comments, AWS provider>= 6.0, < 7.0, Tailscale>= 0.24What the user provides
The example takes no Terraform inputs. It needs AWS and Tailscale credentials in the environment, and two edits to your policy file.
Before applying,
tag:example-infraandtag:example-appconnectorneed owners, or key creation fails. Every example in the repo needs this.After applying, the app connector definition has to be added by hand. Terraform creates the split DNS entry and the device key, but not this. The provider has no app connector resource, and the definition lives in
nodeAttrsin the policy file. The only way to write that from Terraform istailscale_acl, which replaces the whole policy file, so no example in this repo uses it.The README shows the stanza, and the
s3_domainands3_advertised_routesoutputs give the two values that need filling in.