# Smokescreen CONNECT Proxy for Controlled Egress

> Smokescreen is a Go HTTP CONNECT proxy that applies mTLS client authentication, hostname ACLs, and public-IP checks before allowing outbound connections. It fits internal services that need controlled external access, but it is not a general-purpose forward proxy.

**stripe/smokescreen** — A simple HTTP proxy that fogs over naughty URLs    

- Repository: https://github.com/stripe/smokescreen
- Stars: 1,371 · Forks: 114
- Language: Go
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/stripe-smokescreen

## Smokescreen's Outbound Network Boundary

Smokescreen solves a specific network-access problem. It is an HTTP CONNECT proxy placed between internal clients and external services, including webhook providers. Instead of allowing each service to reach any external host directly, clients ask Smokescreen to establish a tunnel. The proxy evaluates the requested destination before allowing that connection.

The project applies several controls. A pre-configured hostname ACL limits requests to approved destination hostnames. Smokescreen also resolves each requested domain and requires the result to be publicly routable rather than an internal address. This restriction is intended to prevent compromised internal code from using an external request path to scan an internal network. Operators can add or override address-level decisions with rules for specific IP addresses, ports, or CIDR ranges.

Smokescreen is aimed at organizations that need centralized egress. The README gives financial partners as an example of parties that may need stable egress IP addresses. Centralizing connections also abstracts the originating service from the remote endpoint, although this does not mean that all outgoing traffic can share one unrestricted policy.

This design is narrower than a typical forward proxy. The README explicitly describes HTTP CONNECT and does not document support for ordinary request forwarding. Smokescreen is therefore more appropriate for controlled service-to-service tunneling than for a developer trying to configure a computer-wide web proxy.

## Certificate Authentication and ACL Evaluation

In typical usage, a Smokescreen client connects over mutual TLS. The proxy authenticates the presented client certificate against configurable certificate authorities and certificate revocation lists. It extracts a client identity and uses that identity when evaluating the destination requested through CONNECT.

By default, the identity is the common name in the client TLS certificate. The README also states that the identification function can be replaced. That extension point could help an organization use a certificate subject mapping other than the default, but the README does not show a custom implementation or describe its interface.

Policy evaluation combines client identity, hostname access, DNS resolution, and IP-level decisions. The configured per-client egress ACL determines which destinations that identity may reach. Smokescreen then checks whether the resolved address is publicly routable. Optional rules can block or allow ranges and individual addresses, including port-specific forms.

The CLI includes `--most-specific-ip-rules`. According to its documented description, this mode resolves overlapping IP rules by longest prefix and then port specificity, with deny winning a tie. That option is disabled by default. This distinction matters when an organization expects the narrowest CIDR rule to decide the outcome.

DNS requests can be sent to repeatable `--resolver-address` values. The README states that each DNS exchange picks an address at random. It does not document resolver caching, timeout behavior, handling of multiple answers, or whether address validation occurs again on the connection path. Those points require inspection of the implementation before depending on a particular DNS design.

## Building Smokescreen with Go Modules

Smokescreen is a Go project whose module path is `github.com/stripe/smokescreen`. The repository's `go.mod` declares `go 1.26.0`, so the build environment must use a compatible Go toolchain. The README says Smokescreen generally supports the two most recent Go versions and directs readers to `.github/workflows/test.yml` for the current test configuration.

A normal build includes Prometheus packages:

```bash
go build .
```

To omit Prometheus from the compiled dependency graph, use the documented `smokescreen_no_prometheus` build tag:

```bash
go build -tags=smokescreen_no_prometheus .
```

The resulting binary accepts ordinary non-Prometheus configuration, but startup configuration fails when `--expose-prometheus-metrics` is present. The README also warns that Prometheus support is currently opt-out and is expected to become opt-in in a future release. Build pipelines and container definitions may therefore need to change when that packaging change occurs.

Smokescreen uses Go modules and a custom fork of goproxy. The README says that fork adds context passing and granular proxy connection timeouts. Its dependency instructions reproduce the standard module commands:

```bash
go build
go test
go mod tidy
```

Vendoring uses:

```bash
go mod vendor
```

For a direct dependency, the documented forms are:

```bash
go get dep@v1.1.1
```

and:

```bash
go get dep@commit-hash
```

The first form selects a semantic version. The second selects a commit hash. The README recommends vendoring the dependency after an update.

## Starting Smokescreen and Reading Its CLI

The README gives a direct way to inspect the options compiled into the current checkout:

```bash
go run . --help
```

For an installed binary, the documented equivalent is:

```bash
smokescreen --help
```

The reader should see the proxy options described by the project, including `--config-file FILE`, `--listen-ip IP`, `--listen-port PORT`, `--egress-acl-file FILE`, and the TLS certificate options. Command-line options override values loaded from a file. The documented proxy listener default is port `4750`, and the default connection timeout is `10s`.

A production configuration still requires files whose full schemas are not shown in the README excerpt. The operator must provide a proxy configuration, an egress ACL, a server key and certificate bundle, a client CA file, and a CRL file when those controls are used. The exact contents depend on the certificates and policy needed by the deployment.

Smokescreen also supports `--proxy-protocol`. The `--allow-self-connections` option permits connections to local interface addresses on all ports, but the CLI states that normal IP and ACL checks still apply. Repeated `--deny-range RANGE`, `--allow-range RANGE`, `--deny-address value`, and `--allow-address value` flags add address rules.

The README does not give a complete first-run configuration with matching ACL and certificate contents. A tutorial should stop at that documented boundary rather than present invented file syntax.

## Smokescreen Container and Metrics Configuration

The repository's `Dockerfile` expects a release packaging context containing `amd64/` and `arm64/` directories populated from verified tarballs. It copies the architecture-specific `smokescreen` binary into a distroless non-root image, runs as UID and GID `65532`, exposes port `4750`, and starts the proxy with the documented listener flags:

```dockerfile
ENTRYPOINT ["/smokescreen"]
CMD ["--listen-ip", "0.0.0.0", "--listen-port", "4750"]
```

Because the image has a non-root runtime identity, mounted ACL, certificate, CRL, and configuration files must be readable by that identity. The `Dockerfile` does not document those file permissions.

Prometheus support is included by default in a normal build. The metrics endpoint is enabled with `--expose-prometheus-metrics`, uses `/metrics` by default, and listens separately on port `9810` by default. The documented format options are `legacy`, `dual`, and `v2`, with `legacy` as the default. The metrics interface can also be bound to a specific IP and endpoint.

The proxy and metrics listeners are configured independently. Binding Prometheus to a restricted interface matters because the metrics listener otherwise defaults to `0.0.0.0`. The README lists the default but does not document the emitted metric names, labels, or their relationship to denied connections. Those details must be checked in the source before configuring alerts or dashboards.

StatsD output can be directed through `--statsd-address ADDRESS`, whose documented default is `127.0.0.1:8200`.

## Limits of Smokescreen's Filtering Model

Smokescreen can deny legitimate traffic when policy is incomplete or DNS returns an address outside the permitted scope. An untrusted, expired, or revoked client certificate can cause authentication to fail. A hostname can pass an ACL entry yet still fail if DNS resolution produces a non-public address. Operators therefore need to distinguish certificate rejection, hostname denial, address denial, and connection failure when diagnosing behavior.

The public-address rule is deliberate, but it also makes Smokescreen a poor fit for proxying traffic to private services. The `--allow-self-connections` option does not bypass all controls. Its documented description says normal IP and ACL checks still apply.

The `--unsafe-ip-filter-bypassed-domain DOMAIN` option introduces a narrower bypass. It skips IP filters for the named domain or `*.domain` glob while retaining ACL and self-connection checks. The CLI tells operators to trust the domain's DNS. This creates a specific dependency between policy correctness and control of that domain's DNS records.

Smokescreen also does not address every outbound-network requirement. The README does not describe ordinary forward-proxy behavior, per-request HTTP filtering, caching, user authentication, or non-CONNECT protocol support. Those omissions do not prove the features are impossible, but they mean adopters cannot justify a deployment from the published documentation alone.

The centralized proxy becomes part of the availability path for client services. Clients need valid certificates, resolvable destinations, synchronized certificate revocation information, and current ACLs. The project solves unwanted egress, but it also introduces a policy component that must be operated deliberately.

## Smokescreen Releases, Upgrades, and License

The repository is not archived. Its last push was on 2026-10-12, and the documented release history contains `v0.1.0`, released on 2026-09-21. That establishes a recent project version and recent repository activity. It does not establish a stable release cadence, a long-term support policy, or a documented upgrade path between versions.

The clearest documented upgrade concern is the planned Prometheus packaging change. Builds currently include Prometheus unless the `smokescreen_no_prometheus` tag is used, while the README states that this may become opt-in. A deployment that assumes Prometheus is always compiled into the default binary should track that change.

Smokescreen uses the MIT license, and the repository includes `LICENSE.txt`. That permits reuse and modification under the license's stated conditions. It does not eliminate deployment work involving client certificates, CRL distribution, ACL ownership, DNS, container images, and monitoring configuration.

For an evaluation, the first project-specific checks are concrete: confirm the Go toolchain matches `go 1.26.0`, inspect the egress ACL schema, validate certificate identity mapping, and verify that a no-Prometheus build is not expected to receive `--expose-prometheus-metrics`. Smokescreen fits controlled CONNECT egress, not arbitrary web-proxy use.

## Conclusion

Adopt Smokescreen when an internal service must make controlled outbound connections through a centralized HTTP CONNECT proxy and can supply client certificates and explicit ACL files. Do not choose it for ordinary web browsing or services that require undocumented forward-proxy behavior. Verify the Go version, certificate files, ACL syntax, DNS design, and container file permissions first. Smokescreen uses the MIT license, while its main adoption cost is operating an authenticated proxy and maintaining policies that match each client's actual destinations.

## FAQ

### How does Smokescreen decide whether an outbound destination is allowed?

Smokescreen authenticates the client, applies the client's egress ACL and the configured hostname restrictions, resolves the destination, and checks its IP address. Additional range, address, port, and matching rules can further constrain or permit the connection.

### Is Smokescreen a general HTTP forward proxy?

The README describes Smokescreen as an HTTP CONNECT proxy. It does not document ordinary request forwarding, so the published design should not be treated as a conventional forward proxy.

### How can I build Smokescreen without Prometheus support?

Use the documented `smokescreen_no_prometheus` build tag with `go build`. That binary accepts the usual non-Prometheus configuration but fails during startup configuration if `--expose-prometheus-metrics` is set.

### What identity does Smokescreen assign to an mTLS client?

By default, Smokescreen uses the common name in the client's TLS certificate. The README states that the client identification function can be replaced.

### What happens when a Smokescreen hostname resolves to an internal IP address?

Smokescreen is designed to reject non-public destinations during its address checks. IP rules and bypass options can affect the evaluation, but hostname ACL and self-connection checks still apply where documented.

## Sources

- [Issues](https://github.com/stripe/smokescreen/issues)
- [License: MIT](https://github.com/stripe/smokescreen/blob/master/LICENSE)
- [README](https://github.com/stripe/smokescreen/blob/master/README.md)
- [Releases](https://github.com/stripe/smokescreen/releases)
- [stripe/smokescreen on GitHub](https://github.com/stripe/smokescreen)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stripe-smokescreen
