I’ve been wrestling with a very specific Twingate challenge for the last few months, and I finally have a solution I’m happy to share. The core problem: we have an internal service catalog (a glorified set of spreadsheets and a small internal app) that defines all of our development and staging environments. Keeping Twingate Resources in sync with this catalog was a completely manual process for our team. Every new service or environment meant someone had to log into the Twingate Admin console and click through the UI to create the Resource, assign it to the right Remote Network, and apply the correct policies. It was error-prone and slow.
So, I built a CLI tool in Python that automates the entire sync process. It reads a structured definition from our service catalog (could be a YAML file, a database query, or in our case, a CSV export), compares it to the existing Resources via the Twingate Admin API, and then creates, updates, or archives Resources as needed. The goal was to have our infrastructure-as-code principles extend into our zero-trust access layer.
Here’s a simplified example of the configuration file format it consumes:
```yaml
resources:
- name: "api-staging-payments"
address: "payments.staging.internal.example.com"
remote_network: "Staging AWS VPC"
group_names: ["engineering", "payments-team"]
- name: "db-analytics-prod"
address: "analytics-db.cluster.prod.internal"
remote_network: "Production GCP"
group_names: ["data-engineering", "platform"]
```
The tool’s core function is a plan/apply cycle. It first fetches all existing data and performs a diff. You can see a dry-run before any changes are made. For example:
```bash
python tg_sync.py --config service_catalog.yaml --dry-run
```
This would output something like:
```
Plan Output:
[CREATE] Resource: api-staging-payments
[UPDATE] Resource: db-analytics-prod (Groups modified)
[NO CHANGE] Resource: frontend-prod
[ARCHIVE] Resource: legacy-service (No longer in source catalog)
```
The real power, in my opinion, comes from hooking this into our existing CI/CD pipeline. Whenever a change is merged to our service catalog repository, a GitHub Action runs this tool against our Twingate tenant, ensuring our access configuration is always declarative and up-to-date. It’s eliminated a significant manual toil for our platform team.
Some key details and workarounds I had to implement:
* The Twingate API is generally solid, but it doesn’t have a native "sync" or "idempotent apply" operation for this specific use case—hence building this wrapper.
* I had to add logic to handle "archiving" (not deleting, for safety) Resources that are removed from the source catalog.
* The most complex part was reliably matching existing Resources to source entries, as you can’t set a custom immutable ID. I used a combination of the Resource `name` and `address` to create a reliable mapping key.
The complete code, with setup instructions and some example workflows for GitHub Actions and GitLab CI, is available on GitHub. I’d love for others to try it, open issues, or submit PRs if you’ve tackled similar challenges. Has anyone else here built custom automation around Twingate’s API? I’m particularly curious about how you’re handling policy assignments at scale.
api first
api first
Great to see others pushing infra-as-code into the zero-trust layer! We did something similar with Terraform and a custom data source, but I love the simplicity of a focused CLI.
How are you handling idempotency on updates, especially if someone renames a resource in your catalog? That was a bit tricky for us.
Docs save time