SSH without a Bastion, a Public IP, or an Open Port
IAP TCP forwarding reaches an instance from one Google range after the user is authenticated and authorised, and a firewall rule that also admits 0.0.0.0/0 on port 22 has the bastion's problem back. The range is a literal, tunnel access is granted per instance rather than to every instance in the project, and OS Login is set so the SSH identity is the IAM identity rather than whoever holds a key.
Verification
Static-verifiedPassed: validated and lint-clean (provider-schema-validated for AWS/Azure/GCP; Terraform-language lint elsewhere).
Conformance
- Static validation (fmt · validate · tflint)
- Security scan clean (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-09-14 · how we verify
Use it from the registry
terraform · opentofumodule "iap_tunnel" {
source = "www.iac-bazaar.com/iac-bazaar/gcp-iap-tunnel/gcp"
version = "1.0.0"
}Needs a registry token from /account/tokens. The module itself is free; the account is what identifies you. Full setup: registry docs.
Inputs & outputs
Create a free account to read this module's contract
The declared contract - every input name, type, default and description, plus every output - is shown to signed-in accounts, not to anonymous visitors.
A free account sees the contract of every module in the catalogue. There is no subscription and nothing to buy - the modules are free to download, and they run under Vizier.
Documentation
gcp-iap-tunnel
SSH and RDP through Identity-Aware Proxy, with no bastion, no public IP and
no port open to the internet. Works with Terraform and OpenTofu
(>= 1.6), google provider >= 6.0, < 7.0.
The firewall rule admits one range: 35.235.240.0/20. IAP's proxies
connect to the instance's private address from that range after the user
has authenticated. A rule that also admits 0.0.0.0/0 has the bastion's
problem back. The range is a literal, not an input.
roles/iap.tunnelResourceAccessor at project level is SSH to every
instance. Per instance by default; project-wide needs
accept_project_wide_access.
Without OS Login, the SSH identity is whoever holds the key. OS Login
ties the Linux account to the IAM identity; set on the project unless
enable_os_login = false.
Verification
Static validation runs tofu fmt, init, validate, tflint and checkov.
This module has not yet had a live test, so it is published as statically
validated with its live test pending and does not carry the live-tested mark.
Usage code & full reference need an account
The complete copy-paste usage, the full input/output reference, and operational notes are free with an account - shown here and bundled in the download. Sign in and this section fills in.
- Usage
Related modules
gcp-firewall-policy
A global network firewall policy exists independently of any network; an association puts it in the path, and a policy with a hundred rules and none governs nobody while rendering as fully configured. enable_logging defaults to false on every rule, so a deny that fires leaves no evidence. Refuses a policy with no network, logs every rule unless told not to, and counts the disabled ones.
gcp-service-perimeter
spec is the dry-run configuration and status is the enforced one - two blocks of the same shape, and a perimeter with only a spec is evaluated on every request, logs violations, and blocks nothing. Empty restricted_services is the other way to have none: the perimeter exists, covers the projects, and governs no API.
gcp-recaptcha
A key with a testing score returns that score for every assessment, bots included - right for staging and, on a production key, a filter that filters nothing; allow_all_domains lets any site consume your assessments against your quota. Testing mode refused without acceptance, domains required on web keys, invisible scoring by default; only a backend assessment call turns a token into a decision.
gcp-cloud-ids
Creating the endpoint creates no packet mirroring policy, so an endpoint with nothing mirrored is provisioned, billed by the hour, shown with a green check and has never seen a packet. The mirroring policy is created with it and refused when it mirrors nothing. Cloud IDS detects and never blocks; blocks_traffic is an output that is always false.
gcp-cloud-armor
A global Cloud Armor WAF policy with preconfigured OWASP SQLi and XSS rules enforcing by default, an optional per-client rate limit, and custom IP allow/deny rules - attachable to many backends.
gcp-security-command-center
The findings page is not a pager: a project accumulates thousands of findings with nobody having received a message, and a mute rule silences a whole category, now and in future, with no record why. Streams CRITICAL and HIGH findings to a Pub/Sub topic as a requirement, refuses a mute without a written reason, and refuses a custom detector created DISABLED, which is listed and evaluates nothing.