Пређите на главни садржај
OpenAI

Изградња безбедног и ефикасног заштићеног окружења за омогућавање Codex-а на Windows-у

Аутор: Дејвид Визен (David Wiesen), члан техничког особља

Учитавање…

Када сам се у септембру 2025. придружио инжењерском тиму услуге Codex, Codex за Windows није имао примену заштићеног окружења, што је значило да су корисници оперативног система Windows били приморани да бирају између две исподпросечне опције при коришћењу агената за програмирање привредног друштва OpenAI:

  1. Одобравање готово сваке команде (чак и оних за читање) коју је агент за кодирање желео да изврши, што је неефикасно и напорно. Једна од главних предности коришћења услуге Codex јесте то што не морате сами да обављате сав заморан посао.
  2. Укључивање режима пуног приступа: омогућавање да Codex покреће све команде без одобрења или ограничења, чиме се уклањају препреке по цену надзора.

Codex, наш агент за програмирање, ради на лаптопима пројектаната – било да је то путем CLI-ја, проширења IDE или десктоп апликације. Управља разговором између човека за тастатуром и модела који се извршава у облаку ради обављања закључивања.

Codex се подразумевано покреће са дозволама стварног корисника, што значи да може да уради све што корисник може. Ово је моћно и потенцијално опасно. Модел за кодирање може да наложи контролном окружењу да локално извршава команде, од покретања тестова до читања или уређивања датотеке и креирања Git гране, па подразумевани режим Codex-а настоји да пронађе праву равнотежу између делотворности и безбедности. Овај подразумевани режим омогућава Codex-у да чита датотеке готово било где и уписује датотеке у оквиру вашег радног простора (тј. директоријума из којег покрећете Codex), без приступа интернету осим ако не наведете да га желите. Да би се постигло ово аутоматско ограничавање писања датотека и приступа мрежи у безбедним оквирима, Codex-у је потребно изоловано окружење које заиста спроводи та ограничења.

Заштићено окружење је ограничено окружење за извршавање. Када програмер користи Codex, оперативни систем његовог рачунара покреће команду са смањеним дозволама, а та ограничења се преносе низ стабло процеса. Свака Codex команда је заштићено окружење од почетка, а сваки наследни процес остаје унутар исте границе.

Дијаграм који приказује границе изолације оперативног система у заштићеном окружењу Codex.

Codex-у су потребне функције изолације које спроводи оперативни систем рачунара како би се реализовало ефикасно заштићено окружење. Неки оперативни системи пружају услужне програме који то добро раде (нпр. Seatbelt на macOS-у, seccomp или bubblewrap на Linux-у); међутим, Windows тренутно не пружа ову врсту могућности подразумевано.

Да би Codex био једнако безбедан и пријатан за коришћење на Windows-у као што је већ свуда другде, било је неопходно да имплементирамо сопствено заштићено окружење.

Где постојећи Windows алати нису били довољни

Windows нуди одређене алате и основне алате за изолацију. Иако ниједно од њих није у потпуности испунило наше захтеве, размотрили смо бројна потенцијална решења – конкретно, AppContainer, Windows Sandbox и означавање Mandatory Integrity Control.

AppContainer

  • Шта: AppContainer је изворно Windows заштићено окружење, модел изолације заснован на могућностима, направљен за апликације које унапред тачно знају чему треба да приступе.
  • Зашто: Привлачно је јер нуди стварну границу ОС-а уместо ограничења по принципу најбољег напора.
  • Зашто не: Codex није једна апликација строго ограниченог опсега. Покреће отворене токове рада за програмере: командне линије, Git, Python, менаџере пакета, алатке за изградњу и све друге бинарне датотеке за које агент одлучи да су му потребне. У пракси, то је значило да AppContainer није одговарао природи проблема. Била је то снажна изолација, али за знатно ужу класу радних оптерећења него „пустити агента да ради као програмер“.

Windows Sandbox

  • Шта: Windows Sandbox је лагана виртуелна машина за једнократну употребу компаније Microsoft. Добијате нову Windows радну површину са снажном границом изолације, а све што урадите у њој нестаје када се сесија заврши.
  • Зашто: Занимљиво из очигледних разлога – далеко компатибилније са произвољним софтвером од AppContainer-а, а из безбедносне перспективе представља много јаче изоловано окружење.
  • Зашто не: Codex мора да делује директно у стварној корисниковој радној копији, алатима и окружењу, а не у засебном једнократном десктоп окружењу које би захтевало подешавање и премошћавање између хоста и госта. Такође је имао суштински проблем на нивоу производа: Windows Sandbox чак није ни доступан у Windows Home SKU-овима.

Означавање интегритета за обавезну контролу интегритета (MIC)

  • Шта: Windows има концепт под називом „нивои интегритета“, као што су ниски, средњи и високи, који одређују колико систем верује објектима и процесима. Основно правило је да процес нижег интегритета не може да уписује у објекат са вишим нивоом интегритета, чак и ако би му уобичајена ACL правила то иначе дозволила. На пример, процес ниског нивоа интегритета сматра се мање поузданим, па му Windows блокира уписивање у уобичајене објекте средњег нивоа интегритета, осим ако ти објекти нису изричито поново означени тако да му то дозвољавају.
  • Зашто: MIC је деловао елегантно на папиру–покренути Codex са ниским интегритетом, означити уписиве корене статусом ниског интегритета и препустити Windows-у да свуда другде примени забрану уписа. То би нам обезбедило пут без администраторских овлашћења, иза којег стоји стварни механизам оперативног система.
  • Зашто не: Као и ACL-ови, ознаке интегритета мењају стварни систем датотека хоста, а у овом случају је промена у значењу посебно широка. Означавање радног простора као простора ниског интегритета не значи само да „Codex може овде да пише”. То значи да процеси ниског интегритета уопштено могу тамо да пишу. На стварној машини програмера, то претвара корисникову стварну радну копију у простор ниског интегритета за хост, што је много ризичније од додељивања пажљиво циљаних ACL-ова једном дизајну заштићеног окружења. Чак и ако алатке за програмере средњег нивоа интегритета наставе да раде, основни модел поверења радног простора промењен је на начин који је тешко обуздати, а још теже оправдати.

Пошто смо проценили да су све опције неодрживе, почели смо да осмишљавамо сопствено решење како бисмо корисницима Windows-а пружили квалитетно искуство са Codex-ом.

Први прототип: „заштићено окружење без повишених привилегија”

Наш први радни прототип користио је комбинацију Windows концепата и алатки за имплементацију изолације која нам је била потребна. Од почетка, један од циљева је био да ово функционише без потребе за повишењем привилегија, што значи да Codex не би морао да даје инструкцију кориснику за администраторске привилегије само да би подесио или покренуо изоловано окружење. То је значило схватити како поставити разумна ограничења за две ствари: уписе у датотеке и приступ мрежи.

Ограничавање уписа у датотеке

Ако уопште не бисмо ограничавали уписе у датотеке, имали бисмо безбедносни проблем. Ако бисмо превише ограничили уписивање у датотеке, заштићено окружење би негативно утицало на продуктивност корисника јер би морало стално да тражи одобрење. Да бисмо решили овај проблем, ослонили смо се на два важна градивна елемента Windows-а: SID-ове и токене са ограниченим писањем.

SID-ови нам омогућавају да заштићеном окружењу дамо идентитет

SID, односно безбедносни идентификатор, представља идентитет за који Windows везује дозволе. Сваки корисник има SID, групе имају SID-ове, а чак и једна сесија пријављивања добија сопствени SID. На пример, тренутна пријављена сесија може имати SID као што је S-1-5-5-X-Y. SID додељен локалној групи администратора може бити S-1-5-32-544.

Windows такође омогућава да креирате синтетичке SID-ове који не одговарају стварном кориснику, али и даље могу да се појављују у ACL-овима (листама контроле приступа), који дефинишу ко може да чита/уписује/извршава одређене датотеке или директоријуме. То чини SID-ове корисним основним градивним елементом за наше заштићено окружење: можемо да креирамо SID-ове које ће користити искључиво заштићено окружење Codex-а, без утицаја на било шта друго на машини.

Токени са ограничењем уписа ограничавају где Codex може да мења датотеке

Токени процеса су безбедносни објекти у систему Windows који дефинишу идентитет и привилегије процеса који се извршава. Они одређују које радње процес може да извршава. Токен са ограничењем писања је посебан тип процесног токена који доводи до тога да Windows изврши додатну проверу приступа за операције писања.

Да би упис био успешан, две провере морају да прођу:

  1. Уобичајеном корисничком идентитету (токен „власник“) мора бити дозвољено да то уради
  2. Најмање једном SID-у са листе ограничених SID-ова токена такође мора бити одобрен приступ
Дијаграм под називом „Упис у заштићено окружење захтева и редован кориснички приступ и приступ sandbox-write SID”.

У пракси, ове провере су нам омогућиле да користимо ACL-ове како бисмо тачно дефинисали где заштићено окружење може да мења систем датотека, што је пружило грануларност која нам је била потребна за операције уписа.

Са SID-овима и токенима са ограничењем уписа, наше заштићено окружење без повишених привилегија функционисало је овако:

  1. Подешавање заштићеног окружења је креирало синтетички SID под називом sandbox-write.
  2. SID-у sandbox-write додељен је приступ за писање, извршавање и брисање
    1. Тренутни радни директоријум
    2. Сви додатни writable_roots подешени у config.toml.
  3. Конфигурација заштићеног окружења је експлицитно ускратила том истом SID-у приступ за писање на локацијама „само за читање унутар уписивих“, као што су:
    1. <cwd>/.git
    2. <cwd>/.codex
    3. <cwd>/.agents
  4. Codex је покренуо команде под токеном са ограничењем за писање, чија листа ограничених SID-ова укључује Све, SID тренутно пријављене сесије и синтетички SID sandbox-write.

Овај ток је ефикасно решио проблем ограничења уписивања у датотеке и изгледао је обећавајуће. Сада нам је било потребно решење за ограничење приступа мрежи заштићеног окружења.

Ограничавање приступа мрежи

Ограничавање приступа мрежи је важан део заштићеног окружења; без тога, злонамерни код би могао неовлашћено да изнесе податке са рачунара на интернет. Пошто смо желели да избегнемо захтев за повишење привилегија, имали смо ограничене могућности да поуздано блокирамо мрежни саобраћај. Алатке које смо желели да користимо, попут Windows заштитног зида, углавном није било могуће инсталирати без администраторских дозвола.

Без Windows заштитног зида као опције, ограничили смо оно што смо могли да контролишемо. Покушали смо да подређено окружење буде подразумевано затворено при отказивању за врсте умрежених алата које програмери заиста користе, тако да Git команде, инсталатери пакета итд. не функционишу у заштићеном окружењу и да корисник мора да одобри све операције које приступају интернету. Идеја је била да се очигледни резервни излази учине неупотребљивим: послати саобраћај који подржава прокси ка мртвој крајњој тачки, натерати Git-ов HTTP(S) транспорт да уради исто и учинити да Git преко SSH-а одмах откаже. Поред тога, додали смо мали директоријум denybin на почетак PATH-а и променили редослед у PATHEXT, како би се заменске SSH и SCP скрипте разрешавале пре стварних бинарних датотека.

На пример, ево неких конкретних замена подешавања окружења које смо користили да ограничимо приступ мрежи:

  • HTTPS_PROXY=http://127.0.0.1:9
  • ALL_PROXY=http://127.0.0.1:9
  • GIT_HTTPS_PROXY=http://127.0.0.1:9
  • NO_PROXY=локални хост,127.0.0.1,::1
  • GIT_SSH_COMMAND=cmd /c exit 1
Дијаграм који приказује архитектуру заштићеног окружења са повишеним привилегијама, са правилима заштитног зида и наменским Windows корисником.

То је обухватило велики део уобичајеног саобраћаја који генеришу алати, али је и даље имало само саветодавну улогу. Процес би могао да игнорише окружење, заобиђе PATH или једноставно директно отвори сокете – превише ризично.

Основни приступ подразумевао је компромисе

Као и код сваке занимљиве софтверске примене, први прототип је имао своје предности и мане. Иако је обављао посао користећи само неколико стандардних Windows могућности, омогућавао веома експлицитне и грануларне уписе у систем датотека и покретао се без повишених привилегија – чиме је смањивао потребу да корисници прихватају прекомерне инструкције за повишење привилегија или буду администратори на свом локалном рачунару – имао је неке стварне недостатке, од којих су га неки дисквалификовали да постане наш коначни дизајн:

  • Брзина подешавања – примена ACL-ова радног простора може бити захтевна у зависности од топологије директоријума радног простора.
  • Отисак: Применили смо стварне ACL-ове на систем програмера, иако отисак није нарочито инвазиван јер се сви примењени ACL-ови односе на посебно креирани синтетички SID који користи искључиво заштићено окружење.
  • Семантика коју је тешко променити: Ослањање на ACL-ове за ограничења заснована на датотекама значи да је промена семантике заштићеног окружења скупа и сложена. Док на macOS-у можемо динамички да мењамо начин на који генеришемо .sbpl датотека која се користи за конфигурисање Seatbelt-а, Windows заштићено окружење може захтевати спору и интензивну операцију за прилагођавање ACL-ова.
  • Заштита мреже је слаба. Као што је раније поменуто, било је „саветодавно“, неки програми који су имплементирали сопствени мрежни механизам дефинитивно би га заобишли и није било осмишљено да издржи нападачки код.

Прва три проблема су својствена прилагођеној имплементацији заштићеног окружења која је довољно флексибилна за агентске токове. Међутим, прича о потискивању мреже била је другачија.

Сузбијање мреже је превише важно

Поред тога што злонамерни агент може лако да заобиђе сузбијање мрежног саобраћаја засновано на окружењу, многи добронамерни кодови или бинарне датотеке би га такође заобишли ако не поштују прокси променљиве окружења или ако имплементирају сопствени мрежни код заснован на сокетима. Сматрали смо да је овај аспект довољан разлог за разматрање улагања у бољи режим заштићеног окружења.

Да бисмо постигли боље ограничавање мрежног саобраћаја, желели смо да користимо Windows заштитни зид, који нам омогућава блокирање одлазног мрежног саобраћаја за кориснике или програме. Нажалост, нисмо могли ефикасно да направимо функционално правило заштитног зида које би се примењивало само на команде које покреће Codex окружење из неколико разлога:

  • Windows не дозвољава подударање правила заштитног зида са идентитетом који није примарни идентитет ограниченог токена. То значи да нисмо могли да применимо правило заштитног зида на „било који токен који укључује наш синтетички SID на својој листи ограничених SID-ова“.
  • Иако бисмо могли да креирамо правило заштитног зида које се подудара са одређеном бинарном датотеком, то нам омогућава само да ограничимо приступ мрежи за сам codex.exe. Не би се примењивало на процесе које агент покреће у име корисника, као што су Git или Python процеси.
  • Остале димензије подударања за заштитни зид такође су биле погрешног облика. Правила са опсегом на нивоу корисника и даље су се подударала са стварним Windows корисником у дизајну без повишених привилегија, а не само са ограниченим подређеним процесом. Правила заснована на путањи програма била су сувише груба: могла су да блокирају codex.exe или python.exe уопштено, али не и ово једно позивање python.exe у заштићеном окружењу. Правила заснована на портовима или адресама такође су била потпуно погрешна политика. На пример, нисмо желели да блокирамо порт 443; желели смо да блокирамо произвољан одлазни приступ за ово конкретно ограничено стабло процеса.

Да бисмо правило заштитног зида применили конкретно на своје команде изоловане у заштићеном окружењу, морали смо да их покрећемо као засебни безбедносни идентитет, а не као „стварни“ корисник. Овај приступ нас је усмерио на нови пут, на ком смо ублажили своје ограничење „без подизања привилегија”.

Редизајн: „заштићено окружење са повишеним привилегијама”

Наредна итерација заштићеног окружења, која је наша тренутна примена, захтева повишене администраторске дозволе током подешавања. Стога га називам термином „заштићено окружење са повишеним привилегијама”. На граници на којој Codex покреће команду у систему, заштићено окружење са повишеним привилегијама изгледа као оно без повишених привилегија. И даље покреће подређене процесе под ограниченим токеном – слично томе, токен write_restricted са истом листом ограничених SID-ова [Everyone, Logon, Synthetic]– међутим, безбедносни субјект овог токена више није стварни Windows корисник, већ један од два локална корисника које је креирао сам Codex:

  • CodexSandboxOffline (онај на који се односе правила заштитног зида)
  • CodexSandboxOnline (онај који није обухваћен правилима заштитног зида)

Овај наизглед мали детаљ заправо има велике импликације за заштићено окружење, за то ко може да га користи, као и за сложеност његовог подешавања и извршавања током рада.

Дијаграм који приказује преиначења мрежног окружења за заштићено окружење без повишених привилегија.

Визуелно је сличан прототипу без повишених привилегија, уз увођење правила заштитног зида и наменског корисника Windows-а, који заправо извршава команде. (Међутим, увођење ових нових концепата значи да је потребно више рада на подешавању пре него што заштићено окружење почне да извршава и штити команде.)

Сада нам је потребан првокласни корак за подешавање

Дизајн заштићеног окружења без повишених привилегија имао је једноставан корак подешавања, али он је био релативно мали:

  • Направи синтетички SID ако је потребно
  • Примени ACL-ове за синтетички SID sandbox-write

Заштићено окружење са повишеним привилегијама, међутим, има још задатака.

  • Креирајте синтетички СИД ако већ није креиран
  • Креирајте онлајн и офлајн кориснике у заштићеном окружењу, ако већ нису креирани
  • Чувајте акредитиве новокреираних корисника локално и шифрујте их помоћу Windows Data Protection API-ја (DPAPI) на месту где корисници заштићеног окружења заправо не могу да их прочитају
  • Креирајте правила заштитног зида која блокирају сав одлазни мрежни приступ за корисника CodexSandboxOffline или, ако већ постоје, проверите да ли су исправна

Постоји додатна компликација у фази подешавања. Очекује се да заштићено окружење Codex-а има права приступа за читање еквивалентна правима стварног Windows корисника. У заштићеном окружењу без повишених привилегија, где је SID главног ентитета ограниченог токена био Windows корисник, ово је постигнуто. Међутим, то није бесплатно када субјект постане нови корисник услуге CodexSandbox. Многи релевантни директоријуми у систему Windows додељују дозволе за читање/извршавање групи „Аутентификовани корисници“. Један значајан пример је директоријум профила корисника. Подразумевано, корисници Windows-а не могу да читају директоријуме профила других корисника Windows-а, па чак ни једноставна читања датотека у многим сценаријима не би успела.

Да бисмо то решили, додали смо још један слој у процес подешавања заштићеног окружења – слој за додељивање ACL-ова за читање корисницима изолованог окружења тамо где такви ACL-ови можда још не постоје. На пример, у неке често коришћене Windows директоријуме:

  • C:\Users\<real-user>
  • C:\Windows\
  • C:\Program Files\
  • C:\Program Files (x86)\
  • C:\ProgramData\

Пошто је ова листа директоријума направљена по принципу најбољег напора, а постављање ACL-ова на сваки од њих може бити прилично захтевно, ову логику извршавамо асинхроно, тако да корак подешавања заштићеног окружења, који блокира кориснике, не мора да чека њихов завршетак.

Енкапсулирали смо логику подешавања у њену сопствену бинарну датотеку, делимично како бисмо прелазили границу UAC-а само када је то неопходно. Али дубљи разлог је био архитектонске природе: подешавање заштићеног окружења има суштински другачију улогу од codex.exe. Чување логике за подешавање заштићеног окружења у наменској бинарној датотеци омогућило је да codex.exe остане нормалан оквир без повишених привилегија; спречило је да механизам за подешавање намењен само за Windows непотребно увећава codex.exe на другим платформама; раздвојило је дуготрајнији рад на подешавању од радног века главног процеса; и дало нам је једно место за руковање различитим путањама подешавања које су заштићеном подручју биле неопходне.

Дијаграм који приказује корак подешавања првокласног заштићеног окружења са повишеним привилегијама.

Покретач команди је нова бинарна датотека која заправо извршава корисничке команде

Због начина на који функционишу границе Windows корисника и пријављивања токена, нисмо могли да наставимо да креирамо ограничени токен и покрећемо процес у његовом контексту као што смо могли са заштићеним окружењем без повишених привилегија. Да бисмо заиста покретали команде као други Windows корисник, наша првобитна идеја била је следећи ток:

  • codex.exe се покреће као стварни Windows корисник. Затим, редом, Codex:
    • Позива LogonUserW(...) за корисника заштићеног окружења.
    • Позива функцију CreateRestrictedToken(...) на том токену корисника у заштићеном окружењу.
    • Користећи тај ограничени токен корисника заштићеног окружења, позива функцију CreateProcessAsUserW(...) како би покренуо завршни подређени процес.

У пракси, жељени ток није функционисао због препреке у вези са привилегијама баријере CreateProcessAsUserW(...). То значи да је codex.exe могао да креира ограничени токен за корисника заштићеног окружења, али није могао поуздано да покрене подређени процес са тим токеном са стране границе стварног корисника. Био нам је потребан процес који је већ био покренут као корисник заштићеног окружења – то би омогућило да се корак ограничавања и коначно покретање догоде на страни корисника заштићеног окружења унутар границе, уместо на страни стварног корисника.

Тај захтев је довео до codex-command-runner.exe, нове бинарне датотеке чији је једини задатак да изда ограничени токен и покрене тражену команду. Уместо да тражимо од codex.exe да самостално обави цео ток (стварни корисник → корисник заштићеног окружења → ограничени токен → подређени процес), делимо ток на два дела:

Део 1

  • codex.exe позива CreateProcessWithLogonW(...) да би покренуо codex-command-runner.exe као корисника заштићеног окружења, а да још не користи ограничени токен.

Део 2

  • Унутар покретача, OpenProcessToken(GetCurrentProcess(), ...) отвара сопствени токен покретача, који већ припада кориснику заштићеног окружења.
  • Покретач позива GetTokenInformation(...) како би издвојио SID за пријављивање у заштићено окружење, а затим CreateRestrictedToken(...) ради креирања коначног ограниченог токена.
  • И даље унутар покретача, он позива CreateProcessAsUserW(...) са тим ограниченим токеном да би покренуо стварни подређени процес.
Дијаграм који приказује ток покретача команди за покретање ограничених команди.

Потпуна слика

Алберт Ајнштајн је рекао: „Све треба учинити што је могуће једноставнијим, али не и једноставнијим од тога”. У том духу, наш дизајн је успешно решио сваки проблем. Коначна архитектура има четири слоја која смо претходно обрадили:

  • сам codex.exe
  • codex-windows-sandbox-setup.exe за обављање свих послова у вези са подешавањем који захтевају повишене привилегије
  • codex-command-runner.exe за извршавање команди са ограниченим токеном
  • Подређени процес

На почетку рада на овом пројекту, није ми било сасвим јасно како ће се он на крају развити. Мој приступ је био да започнем инструментирањем могућности заштићеног окружења на граници између Codex-а и оперативног система. Овај приступ у великој мери одговара начину на који је Codex-ово заштићено окружење примењено на macOS-у и Linux-у.

Како сам сазнавао више о конкретним алаткама које Windows пружа, и кроз десетине одлука којима су уравнотежавани безбедност и једноставност коришћења, систем се развио у свој садашњи облик – више бинарних датотека, прилагођени корисници, правила заштитног зида, корак подешавања са повишеним привилегијама, асинхрони процеси и још много тога.

То није нарочито једноставан систем, али сваки елемент сложености додат је из нужде, како би се изградило заштићено окружење које је истовремено безбедно и, колико год је могуће, не омета корисника.

Дијаграм који приказује коначну архитектуру Windows заштићеног окружења.

Усклађивање безбедности са стварном корисношћу

Радећи на томе да корисницима Codex-а на Windows-у пружимо добро корисничко искуство, циљ нам је био да направимо нешто безбедно што не прави компромисе у погледу корисности – сама сврха коришћења Codex-а јесте да агенти могу да обављају посао без ваше сталне пажње.

Једна од највећих лекција из овог пројекта била је да нам Windows није пружио ниједан основни алат који се јасно пресликава на „безбедан аутономни агент за кодирање“. Комбиновали смо неколико алатки и концепата да бисмо изградили нешто кохерентно. Неке почетне идеје су се показале као ћорсокаци. Коначни дизајн био је хибрид ранијих прототипова, од којих је сваки решавао део проблема.

Друга поука је била да је безбедност агента за програмирање сасвим другачија од класичне безбедности апликација. Codex мора да ради у стварним токовима рада програмера. Инжењерски рад је био усмерен на балансирање компатибилности са агентским радним оптерећењима и стварним спровођењем. Та тензија је обликовала компромисна решења у финалном дизајну.

Да ли вас занима како заштићено окружење Codex функционише? Испробајте га.