Get started
- Prerequisites
- Set up the proxy locally
- Create the guardrail policy
- Create a policy set
- Create a deployment
- Create the proxy API token
- Prepare a certificate authority
- Configure the proxy
- Validate and start the proxy
- Route the CLI through the proxy
- Verify the guardrail
- Remove the test bucket
- Next steps
Run a Cloud Workload Security (CWS) proxy locally and block requests that make an R2 bucket public. This walkthrough uses an empty test bucket in your Cloudflare account.
The proxy and cf client run on the same Linux machine. For pipeline runners, application hosts, and shared proxies, refer to Proxy deployment options.
Prerequisites
:::note[Zero Trust subscription required] Your account must have a Zero Trust subscription. The Zero Trust Free plan is sufficient. :::
- A Linux machine or virtual machine with APT or DNF,
curl, andsudoaccess. - A Cloudflare account with access to manage CWS resources and create account API tokens.
- R2 access in the same account and permission to create and configure a test bucket.
- The Cloudflare CLI installed and signed in. Use Node.js 24.5 or later for the client proxy settings in this guide.
- OpenSSL and a terminal on the proxy host.
Set up the proxy locally
1. ### Install the proxyInstall cws-proxy using your Linux distribution's package manager:
sudo curl -fsSLo /etc/apt/sources.list.d/cws-proxy.sources \
https://downloads.cac.cloudflare.com/packages/cws-proxy.sources
sudo apt update
sudo apt install cws-proxy
```
</TabItem>
<TabItem label="DNF (rpm package)">
```sh
sudo rpm --import \
https://downloads.cac.cloudflare.com/packages/keys/cws-package-signing.asc
sudo curl -fsSLo /etc/yum.repos.d/cws-proxy.repo \
https://downloads.cac.cloudflare.com/packages/cws-proxy.repo
sudo dnf install cws-proxy
```
</TabItem>
Confirm that the installed command is available:
cws-proxy --help
For the proxy's Beta terms, license notices, and acknowledgments, refer to Legal.
-
Create the guardrail policy
In the Cloudflare dashboard, select your account and go to Cloud Workload Security > Policies.
Select Add policy and name it
restrict-r2-public-access. In Filters, select Wirefilter and enter:application.name == "Cloudflare" and application.service == "r2" and application.operation == "r2-put-bucket-public-policy"In Rego source, enter this policy. It permits the selected operation only when the request turns off public access:
package policy.cf_r2_no_public_access default valid := false valid if { input.http.request.body.enabled == false }Select Add policy to save it.
-
Create a policy set
Go to Cloud Workload Security > Policy sets.
Select Add policy set and name it
r2-private-buckets. In Policies, select Attach policy, chooserestrict-r2-public-access, and select Attach policies.Turn on Enforce for the policy. Leave Workloads empty for this walkthrough, then select Add policy set.
-
Create a deployment
Go to Cloud Workload Security > Deployments.
Select Add deployment and name it
cws-r2-test. In Policy sets, select Attach policy set, chooser2-private-buckets, and select Attach policy sets.In Deployment settings, choose Default allow for Default mode. This permits requests outside the guardrail's filter. Select Add deployment to save it.
Open the deployment and copy its ID. Also copy your Cloudflare Account ID.
-
Create the proxy API token
In the same account, go to Manage account > Account API tokens.
Create a custom account token with the Cloud Workload Security Deployment permission. Save the token for the proxy configuration.
This token loads CWS configuration. Your signed-in
cfclient uses its own credentials for R2 requests. -
Prepare a certificate authority
The proxy needs a certificate authority (CA) certificate and its matching private key. Clients need to trust the CA certificate.
To create a local test CA, save this configuration as
openssl.cnf. If you already have a CA pair, use those files instead.[req] prompt = no distinguished_name = subject x509_extensions = v3_ca [subject] O = Example Inc CN = CWS Local Proxy CA [v3_ca] basicConstraints = critical,CA:true keyUsage = critical,keyCertSign,cRLSign subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuerGenerate the certificate and private key:
umask 077 openssl genrsa -out ca-key.pem 4096 openssl req -config openssl.cnf -key ca-key.pem -new -x509 -days 730 -sha256 -out ca-cert.pemKeep
ca-key.pemon the proxy host. Configure clients withca-cert.pemonly. -
Configure the proxy
Save this configuration as
config.yaml. Replace<ACCOUNT_ID>and<DEPLOYMENT_ID>with the values you copied. Use absolute certificate paths if the files are outside your working directory.cws: api_base_url: "https://api.cloudflare.com/client/v4" api_poll_interval_secs: 30 api_token_env: "CWS_DEPLOYMENT_TOKEN" account_id: "<ACCOUNT_ID>" deployment_id: "<DEPLOYMENT_ID>" proxy: logging: format: json verbosity: INFO listen_addr: "127.0.0.1:8080" tls_interception: ca_cert: ./ca-cert.pem ca_private_key: ./ca-key.pem extra_root_cas: [] upstream: proxy: http_proxy: null https_proxy: null ca_cert: null no_proxy: null redis: enabled: falseapi_token_envcontains an environment variable name, not the token value. This local example binds the proxy to loopback and does not require a Redis server.For other authentication modes, upstream proxies, logging, and Redis options, refer to Proxy configuration.
-
Validate and start the proxy
In the terminal that runs the proxy, set your token and validate the file:
export CWS_DEPLOYMENT_TOKEN="<DEPLOYMENT_API_TOKEN>" cws-proxy --config config.yaml --config-testSuccessful validation prints
CWS proxy configuration is valid. It checks the local configuration, not API access.Start the proxy in that terminal:
cws-proxy --config config.yamlKeep the terminal open. Wait for
remote_config_loadedandaction_mapper_loadedin the logs before sending requests. Do not point this terminal'sHTTP_PROXYorHTTPS_PROXYvariables at the local proxy. -
Route the CLI through the proxy
Open a second terminal for the client. Replace the certificate path and Account ID, then set:
export HTTP_PROXY="http://127.0.0.1:8080" export HTTPS_PROXY="http://127.0.0.1:8080" export NODE_USE_ENV_PROXY=1 export NODE_EXTRA_CA_CERTS="<ABSOLUTE_PATH_TO_CA_CERT_PEM>" export CLOUDFLARE_ACCOUNT_ID="<ACCOUNT_ID>"NODE_EXTRA_CA_CERTSpoints to the CA certificate, not its private key. These variables apply to thecfclient in this terminal. Make sureNO_PROXYandno_proxydo not bypassapi.cloudflare.com. -
Verify the guardrail
In the client terminal, create an empty test bucket and inspect managed public access:
cf r2 buckets create --name cws-r2-guardrails-demo cf r2 buckets domains managed list --bucket-name cws-r2-guardrails-demoThe managed-domain result should contain
"enabled": false. Use a different bucket name if this name already exists in your account.First, confirm the policy permits turning off public access:
cf r2 buckets domains managed update cws-r2-guardrails-demo --enabled falseThis request should succeed. Then attempt to turn on public access:
cf r2 buckets domains managed update cws-r2-guardrails-demo --enabled trueThe request should fail with HTTP status
403and aCWS.Errorresponse. Check the managed-domain result again to confirm public access remains off.If the request succeeds, immediately turn off public access with
--enabled false. Check that the CLI uses the proxy, the deployment contains your policy set, and Enforce is on. For further checks, refer to Requests expected to be blocked succeed. -
Remove the test bucket
In the client terminal, delete the empty bucket:
cf r2 buckets delete cws-r2-guardrails-demoConfirm the deletion when prompted.
Next steps
To apply guardrails outside this local walkthrough, review Proxy deployment options.
To target specific request groups or add more policies, follow Configure policies. For destination controls, follow Manage traffic scope.
For startup, certificate, or unexpected request results, refer to Troubleshooting.