Ringkasan Utama
Agar Terraform MCP server aman dijalankan, pin image 1.3.0, muat hanya toolset yang dibutuhkan, biarkan ENABLE_TF_OPERATIONS di default false, dan set MCP_ORGANIZATION_ALLOWLIST di setiap deployment HTTP bersama. Sejak 1.1.0 client tidak bisa lagi menentukan TFE_ADDRESS, dan sejak 1.2.0 panggilan ke organization di luar daftar ditolak.
Saya membuka release notes Terraform MCP server dengan harapan menemukan daftar fitur, dan ternyata isinya lebih mirip changelog keamanan. Keempat rilis dari 1.0.0 sampai 1.3.0 menyentuh apa yang bisa dilakukan caller, header proxy palsu, atau agent yang terlalu bersemangat, dan 1.1.0 membuat client yang tadinya berjalan jadi rusak.
Tulisan ini adalah pembacaan teliti atas release notes, halaman reference, halaman deployment, dan README repositori HashiCorp, ditambah laporan InfoQ tentang pengumuman general availability. Saya belum menjalankan server ini terhadap organisasi HCP Terraform production, jadi setiap flag dan default di bawah berasal dari halaman yang saya baca pada 17 Oktober 2026, dan bila dua halaman tidak sepakat, saya katakan terus terang.
Apa sebenarnya yang dibawa general availability ke mesin Anda
Server ini adalah jembatan open-source antara MCP client dan Terraform. Laporan InfoQ tanggal 13 Juni menyebut kegunaan utamanya: mencari dokumentasi registry, menjelaskan file plan dengan bahasa biasa, dan menjawab pertanyaan tentang workspace. Ia mendukung dua transport, stdio dan StreamableHTTP, dan bisa berjalan lokal untuk satu developer atau sebagai shared service untuk tim. Halaman reference mengelompokkan tool-nya ke dalam tiga toolset.
- registry: mencari provider, module, dan policy publik. Tidak butuh token.
- registry-private: module dan provider privat. Baru terdaftar bila ada TFE_TOKEN yang valid.
- terraform: workspace, run, plan, variable, state, project, dan team. Juga baru terdaftar bila ada TFE_TOKEN yang valid.
Pembagian itu adalah seluruh model keamanannya dalam bentuk kecil. Server tanpa token hanyalah alat pencari dokumentasi; menambahkan token adalah langkah yang mengubahnya menjadi sesuatu yang bisa menyentuh infrastruktur. Jadi anggap token, bukan container, sebagai hal yang Anda berikan akses. Peringatan HashiCorp sendiri tegas: server ini tidak boleh dipakai dengan MCP client atau LLM yang tidak tepercaya, karena bisa membuka data Terraform.
Empat rilis dalam sebelas minggu, dibaca sebagai log keamanan
Release notes berjalan dari 9 Juni sampai 25 Agustus 2026, tepat sebelas minggu. Dibaca berurutan, ceritanya adalah server yang dirilis sebagai alat lokal lalu diperkeras ketika orang mulai menjalankannya sebagai layanan bersama.
| Rilis | Perubahan terkait keamanan | Artinya bagi Anda |
|---|---|---|
| 1.0.0, 9 Juni 2026 | Container berjalan sebagai user non-root. MCP_FORWARD_CLIENT_IP meneruskan IP client lewat X-Forwarded-For pada request keluar. Metrik OpenTelemetry mencatat nama dan versi tiap client. get_sentinel_mock ditambahkan. | Image cocok untuk kebijakan Kubernetes yang melarang root. Anda bisa melihat MCP client mana yang terhubung setelah metrik aktif. |
| 1.1.0, 14 Juli 2026 | Breaking: TFE_ADDRESS di header atau query parameter menghasilkan 403, dan X-Forwarded-For tidak lagi dipercaya secara default. Menambah organization allowlist dan force_unlock_workspace di balik ENABLE_TF_OPERATIONS. | Set TFE_ADDRESS di server. Jika ada proxy di depannya, set MCP_XFF_TRUSTED_HOPS sesuai jumlah proxy yang Anda jalankan. |
| 1.2.0, 4 Agustus 2026 | Panggilan dengan terraform_org_name yang tidak ada di MCP_ORGANIZATION_ALLOWLIST ditolak. delete_project hanya terdaftar dengan ENABLE_TF_OPERATIONS. TF_MCP_SHARED_SECRET mengirim header X-Tf-Mcp-Secret ke backend. /health mendapat field version. | Allowlist diberlakukan per panggilan mulai di sini. Pakai /health untuk memastikan versi mana yang sebenarnya menjawab. |
| 1.3.0, 25 Agustus 2026 | Enam tool team: list_teams, get_team, create_team, add_team_member, grant_team_access, dan delete_team. delete_team hanya terdaftar dengan ENABLE_TF_OPERATIONS. Juga whoami dan get_project. | Permukaan tool bertambah di setiap rilis minor. Cek ulang apa yang kini bisa dijangkau token Anda setelah tiap upgrade. |
Catatan 1.1.0 juga memuat tiga perbaikan yang penting jika Anda pernah menjalankan 1.0.x sebagai layanan HTTP bersama: validasi allowlist kini memakai bearer token yang sama dengan request ke Terraform API, yang menutup bypass lewat header TFE_TOKEN yang bertentangan; pemakaian ulang token lintas tenant di stateless HTTP mode diperbaiki; dan client cache per sesi yang melewati validasi per token diperbaiki. Saya membacanya sebagai pengakuan bahwa mode bersama punya celah sebelum 1.1.0. Allowlist tercatat di 1.1.0 dan penolakan per panggilan di 1.2.0, jadi pakai 1.2.0 atau lebih baru sebelum Anda mengandalkannya.
Tiga gerbang, dan apa yang tidak dihentikan masing-masing
Tidak ada satu kontrol pun yang cukup, karena masing-masing menghentikan hal yang berbeda. Kolom yang berguna di tabel berikut adalah kolom kanan: apa yang dibiarkan terbuka oleh sebuah gerbang adalah apa yang harus ditutup gerbang berikutnya.
| Kontrol | Yang dihentikan | Yang dibiarkan terbuka |
|---|---|---|
| Scope token (TFE_TOKEN, atau bearer token lewat HTTP) | Apa pun yang dilarang oleh izin token itu sendiri. Tanpa token, toolset registry-private dan terraform tidak pernah terdaftar. | Semua yang boleh dilakukan token. Halaman deployment meminta Anda membatasi izinnya, karena server tidak akan mempersempitnya untuk Anda. |
| --toolsets atau --tools | Tool di luar daftar tidak diekspos ke client sama sekali. | Apa pun di dalam toolset yang dipilih. Kedua flag tidak bisa dipakai bersamaan, dan defaultnya berbeda di dua halaman resmi (lihat di bawah). |
| ENABLE_TF_OPERATIONS (default false) | Registrasi action_run, delete_workspace_safely, force_unlock_workspace, delete_project, dan delete_team, serta opsi auto_approve dan is_destroy pada create_run. | Tool yang tidak dicantumkan docs sebagai terkunci, termasuk create_workspace dan update_workspace, yang di halaman yang sama disebut berpotensi destruktif. |
| MCP_ORGANIZATION_ALLOWLIST (khusus HTTP) | Panggilan yang menyebut organization di luar daftar. Jika aktif, bearer token harus bisa menjangkau minimal satu organization yang terdaftar; pencocokan tidak membedakan huruf besar kecil. | stdio, yang tidak menyediakan flag ini. Saya juga tidak menemukan keterangan bahwa ia menyaring tool yang tidak punya argumen organization. |
| Jaringan: bind loopback, TLS, gateway | Akses tanpa autentikasi dari host lain. Mode HTTP bind ke 127.0.0.1 secara default. | Caller yang memang sudah menjadi client resmi. Posisi di jaringan bukan identitas. |
Dibaca dari atas ke bawah, urutan pertahanannya: jangan beri server token yang tidak dibutuhkan, jangan daftarkan tool yang tidak akan dipakai, biarkan lima tool destruktif mati, batasi organization, lalu batasi jaringan. Melewatkan baris pertama karena baris-baris berikutnya ada adalah kesalahan yang hendak dicegah tabel ini.
Setup lokal yang tidak bisa menjangkau production
Untuk satu developer di stdio, config paling aman adalah yang tidak bisa merusak walaupun modelnya dimanipulasi. Contoh client di README membawa token di argumen Docker, yang tidak masalah untuk percobaan pertama tetapi salah untuk file yang disinkronkan ke repositori dotfiles. Ada juga satu hal yang perlu dipastikan: README menyebut registry sebagai toolset default, sedangkan halaman reference mengatakan bahwa tanpa --toolsets server mengaktifkan semua toolset. Tanpa token keduanya hanya memberi registry, tetapi dengan token hasilnya bisa berbeda, jadi sebutkan toolset secara eksplisit.
// Wrong: a literal token in a config file that gets synced or committed,
// and no decision about which toolsets load or how the server is bounded.
{
"mcpServers": {
"terraform": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "TFE_ADDRESS=https://app.terraform.io",
"-e", "TFE_TOKEN=paste-a-token-here",
"hashicorp/terraform-mcp-server:1.3.0"
]
}
}
}
// Right: values live in the client's env block (kept out of the args), the
// image is pinned, and ENABLE_TF_OPERATIONS is simply absent, so it stays false.
{
"mcpServers": {
"terraform": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "TFE_ADDRESS",
"-e", "TFE_TOKEN",
"hashicorp/terraform-mcp-server:1.3.0"
],
"env": {
"TFE_ADDRESS": "https://app.terraform.io",
"TFE_TOKEN": "paste-a-narrowly-scoped-token-here"
}
}
}
}Jika Anda hanya butuh pencarian dokumentasi dan module, lewati token sama sekali. Itu setup lokal terkuat, karena toolset Terraform tidak bisa terdaftar tanpa token.
# Registry only, no token: the registry-private and terraform toolsets
# register only with a valid TFE_TOKEN, so this is a documentation search tool.
claude mcp add terraform -s user -t stdio -- \
docker run -i --rm hashicorp/terraform-mcp-server:1.3.0
# Binary form, when you want to name the toolset instead of inferring it.
# --toolsets and --tools cannot be combined.
terraform-mcp-server stdio --toolsets registryBuat team token khusus untuk agent dan beri nama sesuai agent-nya. Ketika sesuatu tampak janggal di audit trail HCP Terraform, token bernama agent-readonly memberi tahu siapa yang harus ditanya; token pribadi Anda tidak memberi tahu apa-apa.
Lima tool di balik ENABLE_TF_OPERATIONS
ENABLE_TF_OPERATIONS adalah saklar registrasi, bukan izin. Saat false, tool destruktif tidak ada di daftar tool, sehingga model tidak bisa memanggilnya walaupun sebuah prompt injection memintanya. Halaman reference menyebut lima tool yang membutuhkannya, dan mengatakan create_run membutuhkannya untuk membuka opsi auto_approve dan is_destroy.
| Tool | Toolset | Efek menurut halaman reference | Dikunci ENABLE_TF_OPERATIONS |
|---|---|---|---|
| action_run | terraform | Menerapkan, membatalkan, atau membuang run; bisa apply atau destroy infrastruktur | Ya |
| delete_workspace_safely | terraform | Menghapus workspace secara permanen | Ya |
| force_unlock_workspace | terraform | Membuka paksa workspace yang macet; butuh izin admin | Ya (ditambahkan di 1.1.0) |
| delete_project | terraform | Menghapus project; gagal jika masih berisi workspace atau Stacks | Ya (ditambahkan di 1.2.0) |
| delete_team | terraform | Menghapus team secara permanen | Ya (ditambahkan di 1.3.0) |
| create_run | terraform | Membuat run; opsi auto_approve dan is_destroy membutuhkan variabel tersebut | Sebagian |
| create_workspace, update_workspace | terraform | Disebut berpotensi destruktif, tetapi tidak dicantumkan sebagai butuh variabel tersebut | Tidak |
Baris terakhir adalah celahnya. Dengan variabel mati, agent yang memegang token write biasa tetap bisa membuat dan mengubah workspace, dan menurut pembacaan saya atas docs ia bisa mengantrekan run yang berhenti sebelum auto-approval. Itu default yang layak, karena analisis plan lewat pembaca plan dan run adalah kegunaan utamanya, tetapi artinya variabel itu bukan jawaban lengkap. Jawabannya adalah tokennya: jika agent hanya perlu membaca, buat token yang hanya bisa membaca.
Menjalankannya sebagai layanan HTTP bersama
Halaman deployment merekomendasikan API gateway dengan autentikasi, TLS, dan IP allowlisting di antara client dan server, dan mengirim server dengan CORS strict serta daftar origin kosong secara default. Config di bawah menjaga port yang dipublikasikan tetap di loopback sehingga hanya gateway itu yang bisa menjangkaunya, mengatur organization allowlist, dan membiarkan ENABLE_TF_OPERATIONS tidak diset. README mewajibkan MCP_TLS_CERT_FILE dan MCP_TLS_KEY_FILE untuk deployment non-localhost, jadi akhiri TLS di gateway atau set kedua variabel itu.
# Shared service. TRANSPORT_HOST=0.0.0.0 is for inside the container;
# the host-side publish stays on loopback so only a gateway you run can reach it.
# ENABLE_TF_OPERATIONS is deliberately absent: its default is false.
docker run -d --name terraform-mcp --restart unless-stopped \
-p 127.0.0.1:8080:8080 \
-e TRANSPORT_MODE=streamable-http \
-e TRANSPORT_HOST=0.0.0.0 \
-e TFE_ADDRESS=https://app.terraform.io \
-e MCP_ORGANIZATION_ALLOWLIST=acme-platform,acme-sandbox \
-e MCP_CORS_MODE=strict \
-e MCP_REMOTE_IP_METHOD=RemoteAddr \
-e MCP_RATE_LIMIT_GLOBAL=5:10 \
-e MCP_RATE_LIMIT_SESSION=2:5 \
hashicorp/terraform-mcp-server:1.3.0
# Defaults are 10:20 global and 5:10 per session (rps:burst). The tighter
# values above are my choice for agents that can loop, not a HashiCorp number.
# A client then points at the endpoint (README form):
claude mcp add --transport http terraform http://localhost:8080/mcpSatu jebakannya adalah IP client. Sejak 1.1.0 server memakai RemoteAddr dan mengabaikan X-Forwarded-For, yang memang benar, tetapi artinya di belakang gateway setiap request tampak berasal dari gateway. Jika Anda ingin alamat per client, set MCP_REMOTE_IP_METHOD ke X-Forwarded-For dan MCP_XFF_TRUSTED_HOPS tepat sejumlah proxy yang Anda jalankan. README memperingatkan bahwa nilai lain membuat client bisa memalsukan alamatnya.
Di mana setup ini masih bocor
Biaya pertama adalah upgrade. Jika ada client Anda yang mengirim TFE_ADDRESS di header atau query parameter, 1.1.0 menjawabnya dengan 403, dan token di query parameter ditolak dengan 400. Perbaikannya di sisi server: set TFE_ADDRESS di sana dan berhenti mengirimnya. Itu desain yang lebih baik, karena client yang bisa memilih host Terraform bisa mengarahkan server ke host yang ia kendalikan, tetapi akan terlihat seperti outage sampai Anda menemukan barisnya di catatan rilis.
Biaya kedua adalah stdio. Flag organization allowlist hanya tercantum di opsi streamable-http, jadi developer yang menjalankan server stdio lokal dengan token yang luas hanya dilindungi oleh token itu. Ketiga adalah TF_MCP_SHARED_SECRET, yang merupakan kredensial statis yang dikirim di header; README meminta agar hanya dipakai lewat TLS.
ENABLE_TF_OPERATIONS adalah saklar tingkat server. Saya tidak menemukan varian per client atau per sesi di docs, jadi menyalakannya mengaktifkan tool destruktif untuk semua client instance itu sekaligus. Jika Anda membutuhkannya untuk sesi yang diawasi, jalankan instance kedua di port lain dan jauhkan dari gateway bersama.
Semua ini tidak membuat server aman dipakai dengan model yang tidak tepercaya. Kontrol-kontrol ini membatasi kerusakan; mereka tidak membuat prompt injection mustahil, dan itulah sebabnya saran HashiCorp sendiri adalah menghindari client dan LLM yang tidak tepercaya sama sekali.
Yang dikerjakan hari Senin
Lima langkah, berurutan, masing-masing cukup murah untuk selesai sebelum makan siang.
- Pin tag image ke 1.3.0 dan baca release notes antara tag Anda sekarang dan berikutnya sebelum menaikkan versi minor.
- Mulai setiap instance dengan toolset registry tanpa token, dan tambahkan token hanya ketika sebuah tugas benar-benar butuh data workspace.
- Ketika menambah token, buat team token khusus dengan izin tersempit yang masih berfungsi, dan biarkan ENABLE_TF_OPERATIONS tidak diset.
- Untuk deployment bersama, set MCP_ORGANIZATION_ALLOWLIST, jaga port yang dipublikasikan tetap di loopback di belakang gateway ber-TLS, dan set MCP_XFF_TRUSTED_HOPS ke angka yang tepat atau jangan disentuh.
- Jalankan tiga pengecekan di bawah sekarang dan lagi setelah setiap upgrade.
# 1. What the running container actually has. If ENABLE_TF_OPERATIONS=true
# shows up on a box agents can reach, that is the finding.
docker inspect terraform-mcp \
--format '{{range .Config.Env}}{{println .}}{{end}}' \
| grep -E '^(ENABLE_TF_OPERATIONS|MCP_ORGANIZATION_ALLOWLIST|TFE_SKIP_TLS_VERIFY|MCP_REMOTE_IP_METHOD|MCP_XFF_TRUSTED_HOPS)='
# 2. Which version answers. The /health response gained a version field in 1.2.0.
curl -s http://127.0.0.1:8080/health
# 3. The 1.1.0 breaking change as a smoke test. The release notes say a
# TFE_ADDRESS in a header or query parameter gets a 403. I have not
# observed this output myself; anything else is a reason to read the logs.
curl -s -o /dev/null -w "%{http_code}\n" \
"http://127.0.0.1:8080/mcp?TFE_ADDRESS=https://attacker.example"Perintah pertama yang paling berguna. Ia mencetak apa yang benar-benar dipakai container, yang jarang sama dengan isi compose file yang Anda ingat.
Aturan yang saya bawa dari sini: perlakukan MCP server untuk Terraform sebagai kredensial yang dilengkapi menu tool. Setiap kontrol di 1.1.0 sampai 1.3.0 entah mengecilkan menu atau mempersempit kredensial, jadi putuskan keduanya dengan sengaja, pin versinya, dan baca ulang release notes sebelum setiap upgrade minor.

