Agents that need internal systems
Platform, AI and IT teams want agents to read and update the ERP, the ticketing system, an internal REST API or a database. Their first question is control: who is allowed to make what happen.
Agent security architecture
Give AI agents access to internal APIs and on-prem apps without a VPN or inbound ports, with per-agent permissions, approval for risky writes and audit.
Updated Oct 28, 2026
An AI agent that runs in the cloud cannot see applications that live only inside your network. A VPN or a tunnel can make them reachable, but reachable is not the same as controlled. This guide separates the two problems, walks through the common workarounds, and shows what governed access to an internal application looks like: an outbound-only connector, credentials that stay inside, permissions per agent and per action, approval for risky writes, and a record that the agent did not write itself.
A procurement agent spots the parts that need reordering. To finish the job, it has to check live stock and create a purchase order. Both live in the ERP inside your company network.
So someone still opens the ERP, looks up the records and types in the order.
To complete that work, the agent needs access to the internal system. And your team needs to decide exactly what it may do there: read stock, create an order with approval, never delete a supplier.
Contro1 connects those steps. A connector inside your network runs approved operations over an outbound HTTPS connection. You choose which actions each agent can use and which need a person's approval, and every call is recorded.
Watch an agent request a purchase order, a person approve it, and the connector run it inside the network:
The same wall shows up for every team. On your laptop, the agent works. It sees what your machine sees: the VPN, the internal DNS, the staging API, the inventory system on the office network.
Then the agent moves. It becomes a cloud production agent, a scheduled job, or a coding agent running in a cloud sandbox. Suddenly the internal API does not resolve. The database is not there. The ERP is "intranet-only".
This is the question teams keep asking, in their own words: how do we let an agent reach internal APIs, VPN-only resources and private DNS, without making those systems public?
It shows up in two groups.
Platform, AI and IT teams want agents to read and update the ERP, the ticketing system, an internal REST API or a database. Their first question is control: who is allowed to make what happen.
Developers using Claude Code, Cursor or Codex want the agent to reach a staging API, an internal tool or a private registry. Their first question is reach: why can't the agent see what my laptop sees.
Most advice mixes these up. Separating them makes the choices much clearer.
| Reachability | Control | |
|---|---|---|
| The question | Can the agent get a packet to the application? | Should this agent do this action, on this record, right now? |
| Typical tools | VPN, tunnels, zero trust network access, a worker inside the network | Per-agent permissions, policy before execution, approval, audit |
| What it knows about | Hosts, ports, networks, devices | Agents, people, actions, arguments, risk |
| When it is missing | The agent fails with a timeout or a DNS error | The agent succeeds at something nobody wanted |
A network tool answers "may this machine reach that host". It does not know that the call is a DELETE on a customer record, which agent sent it, or who asked the agent to do it.
That is why security teams say permissions should be enforced outside the agent, at the tool or execution layer. The model decides what it wants to do. Something else decides whether it may.
Take the procurement agent. It runs in the cloud. The Plant ERP runs on a server at the plant and has no public API. The agent should not get a VPN, and the ERP should not go on the internet.
Here is what the team decides, action by action:
| Plant ERP action | For the procurement agent |
|---|---|
| Read stock levels | Runs on its own. Reading is routine. |
| Create purchase order | Waits for Finance. A person approves each order before it runs. |
| Cancel purchase order | Not granted. The agent never sees it. |
| Delete supplier | Not granted. Not even published as an Action. |
With a connector, the cloud agent calls an Action. Contro1 checks the grant and the policy. The connector inside the network runs the one operation. The agent gets the answer.
The approver sees the request in plain words, with what the person asked and the reason the agent gave. They approve or reject. Only then does the job reach the connector.
You install a small connector on a machine inside your network. Your agent never talks to the internal system directly. It asks Contro1, Contro1 decides, and the connector does the work inside. Here is the path of one call.
A few details matter to the people who will review this:
The connector is how Contro1 reaches your internal application. Once it is published, that application lives in the same place as every other app your agents use.
That place is the same for every agent in the organization: production agents, coding agents like Claude Code, Codex and Cursor, and personal assistants. Instead of handing each agent its own key to an internal API, every agent reaches it through Contro1.
So the rules your organization already set apply to it too: who owns each agent, what each department, person or agent may do, which steps wait for a person, which instructions agents follow, and one record of everything.
Developers hit this first. The agent in the cloud sandbox has "no local tools, no MCP servers, none of your actual environment". The usual fix is to give the agent your VPN, your SSH keys, or an API key to the internal system.
That works. But nobody decides which records it may change, nobody approves the risky step, and nobody can tell later what it did.
With Contro1, a coding agent gets the same controls as a production agent, from the same place:
The coding agent connects to Contro1 over MCP and calls only the Actions it was granted. Reading order status can run at once. Changing a record waits for you or your lead. It never holds the internal address or the key.
Hooks for Claude Code and Codex send the actions you select, such as deploys, database operations, infrastructure changes or privileged tools, to an approver before they run. Organization-managed settings keep that rule in place for every developer.
Each tool call is reported to Contro1, one trace per run, next to the Actions it ran. You see who asked, which agent, what ran and who approved.
Connecting registers the coding agent as an agent of its own, with its own grants in Access. Your personal access does not flow to it.
| A coding agent reaches internal services through | What it can touch |
|---|---|
| Your VPN or your laptop | Whatever your own access allows on the systems it reaches. No approval, no record. |
| An API key in its environment | Everything the key allows, for anyone who runs the agent |
| A shared service account | Everything that account can do, for every developer |
| Granted Actions through Contro1 | Only the operations you granted, approval where you set it, every call recorded |
Three things. Most teams have them on day one.
REST over HTTPS, or plain HTTP on the same host. An OpenAPI file helps. A PDF of the API documentation also works.
Best the application's own server: Windows Server 2016 or later, a Mac, or a Linux machine with systemd. Not someone's laptop, because calls fail while it is off. It needs outbound HTTPS to api.contro1.com. Nothing inbound.
Pick one task, such as reading stock and creating a purchase order. Start with reads, then add writes with approval.
The connector runs on a server inside your network. Send this section to the person who manages it. With the checks, it takes about 15 minutes.
Two computers, two jobs. On a computer where you are signed in to Contro1, you make the setup file in the on-prem builder. On the server, you install the connector with that file. The server needs no browser and no Contro1 sign-in. Do not run the install on an employee's computer: the connector looks for the application on the computer it runs on.
Which server. The server the application runs on: Windows Server 2016 or later, a Mac, or a Linux machine with systemd. If the application answers over plain http, this is required: the connector sends plain http only to the computer it runs on, at 127.0.0.1. Over https, any always-on server that reaches the application works.
Check first, on that server. The three checks below take two minutes: outbound HTTPS to Contro1, the application's port if you do not know it, and the application answering at 127.0.0.1. If outbound internet is restricted, allow HTTPS to api.contro1.com on port 443. Nothing inbound.
The setup file. In Contro1, open the application in the on-prem builder and type the address it answered on in check 3, for example http://127.0.0.1:3001/api/. Download the file and copy it to the server, into one folder, through Remote Desktop or your remote support tool. The code inside works once, for 10 minutes, so download it when the person on the server is ready. If the application needs an API key, type it into the file on the server. It never leaves it.
Then install. Step 1 downloads the Contro1 CLI, which needs outbound access to contro1.com and github.com as well. If the server cannot reach them, copy the CLI in instead, as shown under the steps.
When status shows Cloud: connected_authenticated, the connector is online. Provider: reachable means the application answered at its address. The service starts again on its own after a restart. Nothing changes on the firewall.
In Contro1, Apps shows the application's state and the server it runs through, such as Working, Connected, address answers or Cannot reach the application, with the reason and what to do. The Connectors list in Apps shows each server and the applications it serves.
Then give it to agents. Until Access says so, nobody can use the application. In Access, give an agent one read first, such as listing records, run it once, and check the result in Activity. Then add writes, with approval.
Another application on the same server: download its setup file and run step 2 again. The same connector serves both.
Behind a corporate proxy, add a proxy_url line to the setup file before step 2. It applies only to traffic to Contro1.
Delete the setup file after installing. Its code is used up, and if you typed a key into it, the connector already keeps it.
What people run into most, and what to do:
| What you see | What to do |
|---|---|
| Invalid URI: Invalid port specified in check 3 | The example port is still in the command. Type the application's own port, from check 2 or from its link. |
| Cannot find path ...connector.json | The setup file is not in this folder. Go to the folder you copied it to, or run dir *connector*.json there to see its exact name. |
| contro1 is not recognized | Run step 1 again in this window, or open a new PowerShell window as Administrator. |
| invalid character when installing | The CLI is older than 0.2.33. Run step 1 again; contro1 --version shows the version. |
| contro1 is running, so ... cannot be replaced | You are on a computer where Claude Code, Codex or Cursor runs Contro1, usually an employee's computer. Install on the server instead. |
| The code expired or was used | Download a new setup file in the builder and run step 2 again. A file that was not installed stops working. |
| Cloud is not connected_authenticated | Outbound HTTPS to api.contro1.com on port 443 is blocked. Allow it, or add proxy_url to the setup file. |
| Cannot reach the application in Apps | Refused: the application is stopped or the port is wrong. No answer: the address is wrong. Fix it in the builder and install a new setup file. |
| The application is in Apps but not offered in Access | Ask your Contro1 contact. The application's operations must be allowed for the organization; publishing does this. |
This is the setup, from the first document to the first approved call.
Start a new app and choose "inside your network". Upload an OpenAPI 3 document, list the operations by hand, or send the vendor's API documentation as a PDF for us to read with you.
Each operation becomes a draft with its method, path, inputs, effect and risk. A POST is at least a medium-risk write. A DELETE is high-risk. Anything unclear stays marked "needs verification" and cannot be published.
Publishing freezes the reviewed operations. The app now appears in Apps, next to your other applications.
Type the internal address and download the setup file on your computer, copy it to the application's server, and install it there, adding the API key there if it needs one. It runs as a Windows service, a macOS daemon or a Linux systemd service. The install steps for your IT team are above.
In Access, choose which agents may use which Actions. A catalog entry alone grants nothing.
Decide which Actions run on their own and which wait for a person, and who that person is.
Every call appears in Activity: the agent, the Action, who approved it, and the result the connector reported.
Steps 1 to 3, in Contro1:
Step 4, the connector:
Every team we talk to has tried at least one of these. Each solves part of the problem.
| Workaround | Why teams choose it | Where it breaks |
|---|---|---|
| VPN on the agent host | Uses what already exists. Simple routing. | Hard to run for many agents. Network rules decide which hosts it can reach, not which business actions it may take. Route changes can drop running sessions. |
| Run the agent inside the network | Private DNS and internal APIs just work. | You now operate agent compute: patching, sandboxing, capacity. The agent still has whatever the host can reach. |
| Tunnel to the internal service | Outbound connection, no inbound port. Tools such as Cloudflare Tunnel or ngrok make this quick. | Makes the service reachable. You still need identity, per-action policy and approval on top, or reachable becomes callable by anything that holds the address. |
| Service account or API key in the agent | Easy. Familiar. | Keys spread across configs and prompts. The agent inherits more authority than the task needs. |
| Custom proxy | Inject credentials, limit endpoints, log calls. | Becomes its own product: auth, rotation, retries, policy, audit, uptime. |
| MCP gateway | One place for auth, routing, secrets and logs. | Many gateways assume the tools are reachable from the cloud. The internal network part is often left to you. |
Here is a checklist built from what engineers and security teams actually ask for. Use it to judge any approach, including ours.
A small service inside your network makes outbound HTTPS calls only. Your firewall stays closed to incoming traffic.
The internal address and the API key are entered on your machine. The agent never sees them. The cloud never stores them.
A person may be allowed to do something. That does not mean every agent acting for that person should inherit the same authority.
"Can use the ERP" is too coarse. Read stock levels: yes. Create a purchase order: with approval. Delete a supplier: no.
The model is not trusted to enforce its own limits. Every call is checked against policy before anything reaches the application.
A person approves the writes that matter. Reads and routine actions run on their own, so approval does not become a button people click without reading.
If the connection drops in the middle of a write, nobody knows if it happened. That write is marked uncertain and a person decides. It is not retried automatically.
Who asked, which agent, which action and arguments, which policy, who approved, and what the application answered.
OWASP Top 10 for Agentic Applications · NIST: AI Agent Standards Initiative
Bring these answers to the review. They are the questions we hear most.
| Question | Answer |
|---|---|
| Do we open any inbound port? | No. The connector makes outbound HTTPS calls only. |
| What must the firewall allow out? | HTTPS to api.contro1.com on port 443, from the connector's server. The one-line install also downloads from contro1.com and github.com; copying the CLI in avoids that. Traffic to your application stays inside your network. |
| Does the cloud store our internal address or API key? | No. They are entered and stored on the connector host. |
| What data passes through Contro1? | The Action's inputs and the application's answer, so Contro1 can check policy and return the result to the agent. Results are size-limited. The address and the credential do not. |
| Can someone send the connector an arbitrary request? | No. It runs only published operations pinned by fingerprint. Jobs carry inputs, not URLs, headers or code. |
| What if a job is forged or replayed? | Jobs are signed and checked before they run, and each job is handed out once. |
| What if the connection drops during a write? | The write is marked uncertain and never retried automatically. A person decides. |
| How is the connector host protected? | It runs under its own service identity. On Windows, secrets are sealed to the machine and the state folder is limited to the service and administrators. |
| Can we use our corporate proxy? | Yes, for the connector's traffic to Contro1. Traffic to your internal API stays on your network. |
| How do we turn it off? | Revoke the agent's grant in Access, or stop the connector. Calls fail at once. |
If one developer needs a coding agent to reach a staging server for an afternoon, an SSH session or a private network tool is fine.
If the agent only reads public data, or the application already has a public API with good scopes, connect it like any other app.
If you want to turn an existing internal API into tools for many agents, for example one that runs on your own servers in AWS, Azure or GCP, the OpenAPI guide covers that case.
You need governed access when the agent writes to an internal system, more than one person or agent relies on it, it runs without someone watching, or you will need to explain later what it did and who allowed it.
Turn an internal API into AI agent tools, without building an MCP server · Armaor MCP: AI agents in Armaor rebar production software, through this connector
Getting a packet from a cloud agent to an internal application is a solved problem. The open problem is what happens next: which agent is calling, for whom, which action, and who said yes.
Tell us which application your agent needs and the first task you want it to complete. We will review the API and deployment requirements with you, then scope an on-prem pilot around that workflow.
Install a connector inside your network that makes outbound HTTPS calls only. The agent calls an Action in the cloud, policy and approval are checked there, and the connector runs the matching operation against your internal API. No inbound port and no VPN on the agent host.
Yes, if the component inside the firewall initiates the connection. An outbound-only connector pulls work from the cloud and sends back results, so the firewall never accepts incoming traffic.
A VPN gives reachability. It lets the agent host reach the network. It does not decide which actions the agent may take, which records it may change, or when a person must approve. You still need permissions per agent and per action, approval for risky writes, and an audit trail.
Avoid giving the agent your VPN, SSH keys, an API key or a shared service account. Instead, connect the coding agent to a control layer over MCP and grant only the internal Actions it needs, with approval for writes. The agent never holds the internal address or credential, and every call is recorded.
Yes, for the actions you select. In Contro1, hooks for Claude Code and Codex send them, such as deploys, database operations or infrastructure changes, to an approver before they run, and organization-managed settings keep the rule in place for every developer. Each tool call is also reported, so you can see what the agent did.
Outside the agent, before the call reaches the application. The model can propose an action, but a separate layer should check the agent's identity, the person it acts for, the action, its arguments and the policy, and stop or route it for approval.
Writes with real impact: creating orders or payments, changing customer or financial records, deleting anything, and actions that are hard to undo. Reads and routine low-risk actions usually run on their own, so approvers are not flooded.
In Contro1 the connector writes a journal entry before each write. If the call may have reached the application but no answer came back, the write is reported as uncertain and is never retried automatically. A person checks and decides.
No. You can upload an OpenAPI 3 document, list the operations by hand, or send the vendor's API documentation as a PDF. In every case each operation is reviewed before it can be published and used by agents.
Use your OpenAPI spec to give AI agents controlled access to a private API. Choose operations, approve sensitive writes, run calls through a private connector.
Use Armaor from Claude, ChatGPT or your own agents over MCP or an API. Choose each action per agent, require approval for writes, and see who did what.
A practical framework for deciding which AI agent actions need human approval - with concrete examples across support, finance, and ops.
Zero Trust for AI agents means every agent action is tied to identity, least agency, human approval, traceability, and signed evidence before it reaches business systems.
Built a useful Claude Code agent? Learn how to share its skills, deploy it for your team, manage permissions and credentials, and govern it as a team agent.
Route selected Claude Code actions to a manager or other eligible reviewer before they run, with production deployment as a practical quickstart example.
Assign the right owner to any AI agent with a five-minute owner test, an ownership matrix, a RACI, and a copy-ready Agent Ownership Record.
Your ERP is the system of record for money and your CRM for customers. AI agents now take real business actions with no system of record at all. Here is what one must capture and how to stand it up fast.