SSD Nodes Learn Hosting plans →
मार्गदर्शक Matt Connorद्वारे Matt Connor

AI agent पासून API keys कशा सुरक्षित ठेवाव्यात

Agent च्या environment मध्ये API key ठेवू नका. Credential gateway मागे scoped, अल्पकालीन token द्या, म्हणजे एका tool call ने खरी key बाहेर जाणार नाही.

AI agents कडून secrets दूर ठेवण्याचा अर्थ

AI agent ही commands चालवणारी सामान्य Linux process असते. त्या process कडे असलेले प्रत्येक environment variable ती चालवत असलेल्या code ला वाचता येते. त्यामुळे agent च्या environment मध्ये API key असल्यास, agent ती key ज्या host पर्यंत पोहोचू शकतो त्या कोणत्याही host कडे पाठवू शकतो. Agent पासून secrets दूर ठेवणे म्हणजे त्याला key ऐवजी तिचा handle देणे. हा handle अल्पकाळ वैध असलेला scoped token असू शकतो किंवा network boundary वर दुसरी यंत्रणा खऱ्या value ने बदलणारा placeholder असू शकतो.

हा model hostile होण्याबद्दलचा विषय नाही. यामागची प्रक्रिया अधिक साधी आहे. Agent instructions असलेले web page, README किंवा issue comment वाचतो आणि त्या पाळतो. कारण language model साठी तुम्ही लिहिलेला मजकूर आणि त्याने fetch केलेला मजकूर यांच्यात फरक नसतो. याला prompt injection म्हणतात. हे घडल्यानंतर होणारे नुकसान नेमके एका गोष्टीने मर्यादित होते: process काय वाचू शकते. तुम्ही अद्याप boundary निश्चित केली नसेल, तर server वर coding agent सुरक्षितपणे चालवणे या मार्गदर्शकाचा आधार असलेल्या isolation स्तरांचे वर्णन करते.

धोका-प्रतिमान सोप्या भाषेत

तुमचा agent ज्या user म्हणून चालतो, त्या user म्हणून हे चालवा.

tr '\0' '\n' < /proc/self/environ | grep -iE 'key|token|secret|password'

यातून छापली जाणारी प्रत्येक ओळ एखाद्या अनोळखी सर्व्हरला पाठवलेल्या एका HTTP request इतकीच दूर असते. आता agent जवळच्या disk वर काय उपलब्ध आहे ते पाहा.

grep -rIl --exclude-dir=.git -e 'API_KEY' -e 'SECRET' ~/projects
find ~ -maxdepth 3 -name '.env' -o -name 'credentials' -o -name '*.pem'

shell असलेल्या agent ला हा data बाहेर पाठवण्यासाठी हुशार exploit आवश्यक नाही. चार सामान्य मार्ग पुरेसे आहेत आणि log मध्ये ते चारही नेहमीच्या कामासारखे दिसतात:

  • कोणत्याही host कडे जाणारा outbound curl किंवा fetch, ज्यामध्ये value query string मध्ये असते.
  • agent ला write करता येणाऱ्या repository कडे केलेले git commit आणि git push.
  • package install script, जो agent च्या user म्हणून arbitrary code चालवतो.
  • value समाविष्ट असलेल्या hostname चा DNS lookup. HTTP egress block केलेले असले तरी तो value बाहेर पाठवतो.

फक्त review करून ही समस्या सुटणार नाही. योग्य उपाय म्हणजे agent च्या आवाक्यात कोणताही मौल्यवान data उपलब्ध नसल्याची खात्री करणे.

कामाच्या tree मधील secret म्हणजे context window मधील secret

Agent files वाचतो. तो ज्या repository मध्ये काम करत आहे, त्यातील .env file वाचली जाईल. ती वाचल्यानंतर context window मध्ये येते. याचा अर्थ ती transcript मध्ये, तुम्ही ठेवलेल्या कोणत्याही log मध्ये आणि agent पुढे लिहिणाऱ्या कोणत्याही मजकुरात समाविष्ट होते.

पूर्वी, agent ज्या tree मध्ये काम करत होता त्यात key ठेवलेली असताना:

cd ~/projects/billing
cat .env
# STRIPE_SECRET_KEY=sk_live_...
# DATABASE_URL=postgres://app:hunter2@db.internal:5432/billing

नंतर, file आवाक्याबाहेर हलवल्यानंतर:

sudo install -d -m 750 -o root -g agent-review /etc/agent-review
sudo install -m 640 -o root -g agent-review ~/projects/billing/.env /etc/agent-review/billing.env
rm ~/projects/billing/.env

working tree मध्ये file उरलेली नसल्यामुळे agent चा user ती file उघडू शकत नाही. Agent च्या स्वतःच्या config मधील deny rules हा दुसरा स्तर आहे; पहिला स्तर नाही. Claude Code project मधील .claude/settings.json मधून permission rules वाचतो:

{
  "permissions": {
    "deny": ["Read(./.env)", "Read(./secrets/**)", "Read(./**/*.pem)"]
  }
}

यामुळे agent exploration करताना चुकून file उघडण्यापासून थांबतो. हे नियम file tools च्या पलीकडेही लागू होतात. Claude Code Bash मधील त्याला ओळखता येणाऱ्या file commands विरुद्धही हे नियम तपासतो, जसे cat आणि head, तसेच < .env सारख्या redirection च्या targets विरुद्धही तपासतो. मात्र project directory मध्ये grep -r KEY . चालवणाऱ्या injected instruction ला किंवा स्वतः .env उघडणाऱ्या छोट्या Python script ला हे थांबवत नाही. कारण permissions documentation नुसार, file चे नाव न देता files वाचणाऱ्या commands वर किंवा स्वतः files उघडणाऱ्या subprocesses वर deny rules लागू होत नाहीत. अशा परिस्थितीसाठी documentation Claude Code च्या sandbox कडे निर्देश करते. तो operating system स्तरावर block लागू करतो. असा command चालवण्यापूर्वी तुमची परवानगी विचारली जाईल का हे session च्या permission mode वर अवलंबून असते. interactive Claude Code sessions साठी auto mode आता built-in starting mode आहे, त्यामुळे तुम्ही पाहणी करत नसलेल्या server वर असे अधिक commands विनाप्रश्न चालू शकतात. Agent च्या permissions ऐवजी त्याच्या सवयी घडवणाऱ्या कोणत्याही गोष्टीवर हीच मर्यादा लागू होते. agent ला आवश्यक तेवढ्याच किमान बदलापुरते मर्यादित ठेवणारे skill run ला agent ने उघडण्याची गरज नसलेल्या files मध्ये भटकण्यापासून रोखते. तरीही ते model ला समजावून बदलता येणारे guidance असते. Config ला guardrail आणि filesystem permission ला भिंत समजा. Containers मध्येही हाच फरक लागू होतो: Docker Compose मधील env files आणि secrets या समस्येच्या एक स्तर खालील आवृत्तीचे स्पष्टीकरण देते.

प्रत्येक agent साठी स्वतंत्र unprivileged user द्या

agent तुमच्या user म्हणून चालत असल्यास, त्याला तुमच्या SSH keys, cloud credentials आणि shell history यांचा access मिळतो. स्वतंत्र user तयार करण्यासाठी एक command पुरेसा आहे आणि हे सर्व access काढून टाकता येतात.

sudo adduser --disabled-password --gecos "" agent-review
sudo chmod 700 /home/agent-review
sudo -u agent-review cat ~/.ssh/id_ed25519

शेवटची ओळ cat: /home/you/.ssh/id_ed25519: Permission denied सह fail झाली पाहिजे. त्याऐवजी key print झाली, तर agent चा user त्या file पर्यंत पोहोचू शकतो. नावाने file उघडण्यासाठी तिच्या वरील प्रत्येक directory वर search (x) permission आवश्यक असते; read permission आवश्यक नसते. त्यामुळे mode 711 असलेली आणि इतर कोणी list करू न शकणारी home directory असली, तरी key file स्वतः readable असल्यास key पर्यंत पोहोचता येते. chmod 700 ~ path बंद करते आणि chmod 600 ~/.ssh/id_ed25519 key सुरक्षित करते. agent user ला sudo मध्ये add करू नका. तसेच त्याला प्रत्यक्ष आवश्यक असलेल्या एकाच command पेक्षा व्यापक NOPASSWD rule देऊ नका. VPS वरील Least privilege users मध्ये group आणि sudoers संबंधी तपशील दिले आहेत. तुम्ही त्या मशीनवर एकापेक्षा जास्त session चालवू लागल्यावर हे विभाजन लक्षात ठेवा. कारण एक Claude Code session दुसऱ्या session कडे थेट text पाठवू शकते, आणि पहिल्या session कडे असलेली कोणतीही माहिती एका message मधून त्या channel वर जाऊ शकते.

Cloud VPS वर आणखी एक boundary लागू करणे उपयुक्त ठरते. Instance metadata service एका निश्चित link-local address वर उत्तर देते आणि मागणी करणाऱ्या कोणत्याही प्रक्रियेला role credentials देऊ शकते. कोणता local user request करत आहे हे endpoint वर तपासले जात नाही. EC2 बाबत AWS च्या documentation नुसार IMDSv1 calls साठी token आवश्यक नसतो. एका user ला या service पासून दूर ठेवण्यासाठी AWS स्वतः त्या user च्या ID वर आधारित local firewall rule सुचवते.

sudo iptables -I OUTPUT 1 -p tcp -m owner --uid-owner agent-review -d 169.254.169.254 -j REJECT

rule वरच्या स्थानी -I वापरून insert करा; -A वापरून शेवटी append करू नका. Default allow outgoing policy असलेल्या ufw वर चालणाऱ्या host मध्ये, ufw ची शेवटची OUTPUT chain प्रत्येक नवीन TCP connection स्वीकारते. त्यामुळे शेवटी append केलेल्या rule पर्यंत कधीच पोहोचले जात नाही. Reboot नंतर iptables rules देखील नाहीशा होतात, जोपर्यंत तुम्ही त्या persist करत नाही. Metadata service चे IPv6 endpoint सक्षम केले असल्यास, [fd00:ec2::254], त्याच rule ला ip6tables वापरून जोडा.

agent च्या बाजूने ते तपासा. sudo -u agent-review curl -s --max-time 3 http://169.254.169.254/ ने काहीही print करू नये आणि non zero exit करावा, कारण packet box सोडण्यापूर्वीच reject केला जातो. त्याने listing print केली, तर rule पर्यंत पोहोचले जात नाही.

सीमेवर credential injection करा

ही समस्या प्रत्यक्षात सोडवणारी पद्धत म्हणजे credential injection. Agent कडे कधीही खरी cryptographic key राहत नाही. तो आपली विनंती स्थानिक gateway मार्फत पाठवतो आणि gateway बाहेर पाठवताना placeholder च्या जागी खरे secret ठेवतो. Secret gateway च्या storage मध्ये, वेगळ्या process मध्ये आणि वेगळ्या user च्या मालकीचे असते.

OneCLI ही याची एक open source अंमलबजावणी आहे. त्याच्या ee/ directories वगळता ते Apache-2.0 license अंतर्गत उपलब्ध आहे. ee/ directories साठी स्वतंत्र enterprise license लागू आहे आणि production वापरासाठी subscription आवश्यक आहे. OneCLI agent च्या शेजारी containers मध्ये चालते. October 2026 पर्यंतच्या project documentation नुसार, हा Docker Compose setup compose file च्या शेजारील .env file मधून तीन generated secrets वाचतो:

git clone https://github.com/onecli/onecli.git && cd onecli/docker
cat > .env <<EOF
SECRET_ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
GATEWAY_INTERNAL_SECRET=$(head -c 32 /dev/urandom | base64)
BETTER_AUTH_SECRET=$(head -c 32 /dev/urandom | base64)
COMPOSE_PROFILES=runner
EOF
chmod 600 .env
docker compose up -d --wait

त्या .env file चा backup घ्या, कारण SECRET_ENCRYPTION_KEY गमावल्यास त्यात साठवलेले प्रत्येक secret अनाथ होते. Dashboard port 10254 वर आणि gateway port 10255 वर ऐकतात. Default नुसार दोन्ही 127.0.0.1 वर bind असतात. खरे credential एकदाच साठवा. त्यानंतर प्रत्येक agent ला key च्या जागी placeholder value आणि त्याचा स्वतंत्र scoped access token द्या. Agent हा token Proxy-Authorization header मध्ये पाठवतो. Gateway host आणि path नुसार outbound request जुळवतो, संबंधित credential decrypt करतो आणि placeholder च्या जागी ते ठेवतो. Agent च्या environment मध्ये चोरी करण्यासारखी कोणतीही महत्त्वाची माहिती राहत नाही.

येथील महत्त्व encryption मध्ये नाही. महत्त्वाचे हे आहे की “या agent ने काय आणि केव्हा वापरले?” हा प्रश्न log query ने सोडवता येतो. Key ची प्रत सहापैकी कोणत्या environment मध्ये होती याचा अंदाज घेण्याऐवजी एक audit trail तपासा.

गुपित environment कडे नव्हे, process कडे द्या

तुम्ही agent systemd अंतर्गत चालवत असल्यास environment variables ची अजिबात गरज नाही. LoadCredential= हे गुपित फक्त service चा user वाचू शकतो अशा private directory मध्ये ठेवते. Unit file मध्ये ते %d म्हणून आणि process मध्ये $CREDENTIALS_DIRECTORY म्हणून उपलब्ध होते. ही मर्यादा service वर नव्हे, तर user वर लागू होते. त्यामुळे प्रत्येक agent service साठी स्वतंत्र user द्या. त्याच user म्हणून चालणारी इतर कोणतीही process ही directory उघडू शकते. Unit मध्ये filesystem namespacing वापरल्यास, उदाहरणार्थ PrivateMounts=yes, ही directory इतर services पासून लपवता येते. ही value /proc/<pid>/environ मध्ये कधीही दिसत नाही. त्यामुळे ps eww ती दाखवू शकत नाही. Service थांबल्यावर directory नाहीशी होते.

Credential आधी machine साठी encrypt करा. या commands systemd documentation मधून घेतलेल्या आहेत. त्या systemd 250 किंवा त्यानंतरच्या आवृत्तीवर कार्य करतात. यात Ubuntu 24.04 आणि Debian 13 समाविष्ट आहेत:

echo -n 'sk-example-value' > /tmp/plain.txt
sudo systemd-creds encrypt --name=api_key /tmp/plain.txt /etc/credstore/api_key.cred
shred -u /tmp/plain.txt
sudo systemd-run -P --wait -p LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred \
  systemd-creds cat api_key

शेवटची command sk-example-value प्रिंट करते. यावरून encrypted file या host वर decrypt होत असल्याचे सिद्ध होते. त्यानंतर unit मधून तिचा संदर्भ द्या:

[Service]
User=agent-review
LoadCredentialEncrypted=api_key:/etc/credstore/api_key.cred
Environment=AGENT_KEY_FILE=%d/api_key
ExecStart=/usr/local/bin/agent-worker

तुमचा agent code value आवश्यक असताना $AGENT_KEY_FILE येथील file उघडतो. File read हा क्षणिक असतो. Environment variable process च्या संपूर्ण आयुष्यभर उपलब्ध राहतो आणि ती process सुरू करणाऱ्या प्रत्येक child मध्येही उपलब्ध असतो.

दीर्घकाळ वैध असलेल्या keys ऐवजी अल्पकालीन tokens वापरा

कधीही expire न होणारी key अनेक महिन्यांनंतर log किंवा transcript मध्ये आढळली, तरी ती वैध असते. सेवा session token उपलब्ध करून देत असल्यास, तो session token वापरा आणि कामासाठी अनुमत असलेला सर्वात कमी lifetime सेट करा.

aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/agent-readonly \
  --role-session-name agent-review \
  --duration-seconds 900

AWS STS (security token service) किमान पंधरा मिनिटांचा कालावधी स्वीकारते आणि एका agent task साठी तो सहसा पुरेसा असतो. GitHub साठी agent user ला स्वतःचा gh login द्या आणि तो ज्या एकाच repository वर काम करतो, त्यापुरताच मर्यादित fine grained token वापरा; त्यामुळे त्या session मध्ये gh auth token केल्यावर इतर कोणत्याही गोष्टीवर परिणाम करू न शकणारे credentials मिळतात. प्रथम resource नुसार scope निश्चित करा, त्यानंतर time नुसार.

पडताळा आणि त्यानंतरही पडताळत राहा

एजंटच्या सेटअपमध्ये कोणताही बदल केल्यानंतर या तीन तपासण्या करणे उपयुक्त ठरते. त्या स्वतःच्या वापरकर्त्याच्या नावाने नव्हे, तर एजंटचा वापरकर्ता म्हणून चालवा.

sudo -u agent-review env | grep -iE 'key|token|secret'
sudo -u agent-review ls -la /home/you/ 2>&1 | head -3
sudo -u agent-review curl -s -o /dev/null -w '%{http_code}\n' --max-time 5 https://api.github.com/user

पहिल्या तपासणीने काहीही आउटपुट देऊ नये. दुसऱ्या तपासणीने ls: cannot open directory '/home/you/': Permission denied दाखवावे. यावरून फक्त ती directory list करता येत नाही हे समजते; तिच्यातील फाइल वाचता येत नाही हे सिद्ध करणारी तपासणी आधीची cat आहे. तिसरी तपासणी एजंटच्या network path कडून कोणती identity सादर केली जाते ते दाखवते. gateway pattern कशासाठी आहे याचे हेच उत्तर आहे: 401 याचा अर्थ request GitHub पर्यंत अशा credential शिवाय पोहोचली आहे जी GitHub स्वीकारते; credential पूर्णपणे अनुपस्थित असू शकते किंवा invalid अथवा expired असू शकते. 200 याचा अर्थ valid credential पाठवली जात आहे. त्यामुळे कोणता token वापरला जातो हे तुम्हाला माहीत असावे. तुम्ही agents unattended चालवत असल्यास, VPS वरील AI agent खर्च नियंत्रित करणे या access limits सोबत लागू होणाऱ्या budget limits चे स्पष्टीकरण देते.

FAQ

मी मॉडेलवर माझ्या keys उघड होणार नाहीत यासाठी विश्वास ठेवू शकतो का?

नाही. या threat model मध्ये attacker मॉडेल नसते. Agent web pages, repositories आणि issue trackers मधील मजकूर वाचतो आणि त्या मजकुरात instructions असू शकतात. त्याने fetch केलेल्या मजकुरातील instructions आणि तुमच्या instructions यांमध्ये फरक ओळखण्याचा मॉडेलकडे विश्वसनीय मार्ग नसतो. मॉडेल योग्य निवड करेल यावर अवलंबून असलेले कोणतेही नियंत्रण convincing injected instruction आल्यावर पहिल्याच वेळी अपयशी ठरते. त्यामुळे नियंत्रण operating system किंवा network मध्ये असणे आवश्यक आहे.

Agent secrets साठी environment variables खरोखर इतके धोकादायक आहेत का?

एका विशिष्ट कारणामुळे ते धोकादायक आहेत: ते inherited असतात. Agent सुरू करत असलेल्या प्रत्येक child process ला त्यांची प्रत मिळते. यामध्ये build script, test runner आणि कोणताही package install hook यांचा समावेश होतो. त्याच user कडून /proc/<pid>/environ द्वारे variables वाचता येतात. त्यामुळे agent सुरू करत असलेली कोणतीही गोष्ट agent ने variables पुढे न पाठवता त्यांना वाचू शकते. वापराच्या क्षणी LoadCredential= किंवा gateway द्वारे file वाचल्यास exposure त्या क्षणापुरते मर्यादित राहते.

Secrets vault मध्ये ठेवल्याने ही समस्या आपोआप सुटते का?

अंशतःच. Vault मुळे storage ची समस्या सुटते. तुम्ही तो vault self host करत असल्यास त्याचे स्वतंत्र hardening करावे लागते. कारण Vaultwarden server मध्ये साधारणपणे त्याच्या admin token किंवा backup file द्वारे breach होते, त्यात साठवलेल्या encrypted items द्वारे नाही. शेवटची पायरी मात्र यामुळे सुटत नाही. त्या पायरीवर काहीतरी vault मधून secret काढून ते agent ला environment variable म्हणून देते आणि तुम्ही पुन्हा सुरुवातीच्या स्थितीत जाता. Substitution कोण करतो हे महत्त्वाचे आहे. Agent ने secret fetch केला तर secret agent कडे असतो. Gateway किंवा init system ने agent च्या process च्या बाहेर substitution केली तर agent कडे तो secret कधीच येत नाही.

Agent ने आधीच काही leak केले आहे की नाही हे मला कसे कळेल?

बहुतेक वेळा घटना घडल्यानंतर हे कळू शकत नाही. म्हणून gateway वापरणे महत्त्वाचे आहे. Gateway नसल्यास तुमचे पुरावे shell history, agent transcript आणि तुम्ही कदाचित ठेवत नसलेल्या outbound connection logs मध्ये विखुरलेले असतात. Credential gateway असल्यास credential चा प्रत्येक वापर agent identity आणि timestamp असलेल्या एका ओळीत नोंदवला जातो. Leak झाल्याचा संशय असल्यास प्रथम key rotate करा आणि नंतर तपास करा. Rotation स्वस्त आहे; खात्री स्वस्त नाही.

आज मी किमान काय करावे?

तुमचे सर्व .env files agents ज्या directories मध्ये काम करतात त्यातून बाहेर हलवा आणि प्रत्येक agent साठी एक unprivileged user तयार करा. या दोन बदलांना सुमारे 10 मिनिटे लागतात. त्यामुळे सर्वसाधारण मार्ग बंद होतो: code च्या शेजारी ठेवण्याचे कोणतेही कारण नसलेली credential file agent वाचतो. Gateway आणि short lived tokens हे पुढचे पाऊल आहे; पहिले पाऊल नाही. हाच प्रारंभबिंदू कोणत्याही agent runtime साठी लागू होतो. यामध्ये VPS वर autonomous agent सुरक्षितपणे चालवणे याचाही समावेश आहे.

हा लेख उपयुक्त होता का?