Kako ExpressVPN ohranja svoje spletne strežnike zakrpane in varne

[ware_item id=33][/ware_item]

Strežnik ExpressVPN se dviga iz pepela.


Ta članek razlaga pristop ExpressVPN do upravljanje varnostnih popravkov za infrastrukturo, ki poganja spletno mesto ExpressVPN (ne strežniki VPN). Na splošno je naš pristop k varnosti:

  1. Naredite sisteme zelo težko hecati.
  2. Minimizirajte morebitno škodo če se sistem hipotetično zlomi in prizna dejstvo, da nekaterih sistemov ni mogoče narediti popolnoma varne. Običajno se to začne v fazi arhitekturnega načrtovanja, kjer dostop do aplikacije zmanjšujemo na minimum.
  3. Čim bolj skrajšajte čas da lahko sistem ostane ogrožen.
  4. Preverjanje te točke z rednimi pentesti, notranjimi in zunanjimi.

Varnost je vgrajena v našo kulturo in je glavna skrb, ki vodi vse naše delo. Obstaja še veliko drugih tem, kot so naše prakse pri razvoju varnostne programske opreme, varnost aplikacij, procesi in usposabljanje zaposlenih itd., Vendar te objave niso v dosegu tega delovnega mesta.

Tukaj razlagamo, kako dosežemo naslednje:

  1. Poskrbite, da so vsi strežniki popolnoma zakrpani in nikoli več kot 24 ur za objavami CVE-jev.
  2. Poskrbite, da se noben strežnik ne uporablja več kot 24 ur, s tem postavite zgornjo mejo časa, ki ga napadalec lahko vztraja.

Oba cilja uresničujemo s pomočjo avtomatiziran sistem, ki obnovi strežnike, začenši z operacijskim sistemom in vsemi najnovejšimi popravki, in jih uniči vsaj enkrat na 24 ur.

Naš namen tega članka je biti uporaben za druge razvijalce, ki se soočajo s podobnimi izzivi, in našim strankam in medijem zagotoviti preglednost poslovanja podjetja ExpressVPN..

Kako uporabljamo odgovarjajoče zvezke in Cloudformation

Spletna infrastruktura ExpressVPN gostuje na AWS (v nasprotju z našimi VPN strežniki, ki delujejo na namenski strojni opremi) in močno izkoriščamo njene funkcije, da omogočimo obnovo.

Celotna naša spletna infrastruktura je opremljena z Cloudformation in poskušamo avtomatizirati čim več procesov. Vendar se nam zdi delo s surovimi predlogami Cloudformation precej neprijetno zaradi potrebe po ponavljanju, splošne slabe berljivosti in omejitev skladbe JSON ali YAML.

Za ublažitev tega uporabljamo DSL imenovan cloudformation-ruby-DSL, ki nam omogoča, da v Ruby pišemo definicije predloge v Ruby in izvozimo predloge Cloudformation v JSON.

Zlasti DSL nam omogoča, da uporabniške skripte pišemo kot običajne skripte, ki se samodejno pretvorijo v JSON (in ne gredo skozi boleč postopek pretvorbe vsake vrstice skripta v veljaven niz JSON).

Splošna vloga Ansible, imenovana cloudformation-infrastruktura, skrbi za to, da dejanska predloga postane začasna datoteka, ki jo nato uporabi modul za odgovor v oblaku:

- name: 'render {{komponenta}} skladba oblakov json'
lupina: 'rubin "{{ime_predloga | privzeta (komponenta)}}. rb" razširite --stack-name {{stack}} - regija {{aws_region}} > {{tempfile_path}} '
Arg:
chdir: ../cloudformation/templates
spremenjeno_kdaj: napačno

- ime: 'ustvari / posodobi {{komponenta}} sklad' '
oblačna informacija:
stack_name: '{{stack}} - {{xv_env_name}} - {{komponenta}}'
stanje: prisotno
regija: '{{aws_region}}'
predloga: '{{tempfile_path}}'
template_parameters: '{{template_parameters | privzeto ({})}} '
stack_policy: '{{stack_policy}}'
register: cf_result

V playbook-u večkrat pokličemo vlogo cloudformation-infrastrukture z različnimi komponentami spremenljivkami, da ustvarimo več nizov Cloudformation. Na primer, imamo mrežni niz, ki določa VPC in z njim povezane vire, in paket aplikacij, ki določa skupino samodejnega skaliranja, konfiguracijo zagona, kljuke v življenjskem ciklu itd..

Nato uporabimo nekoliko grd, a uporaben trik, da izhod modula oblakov pretvorimo v spremenljivke Ansible za naslednje vloge. Ta pristop moramo uporabiti, ker Ansible ne omogoča ustvarjanja spremenljivk z dinamičnimi imeni:

- vključujejo: _tempfile.yml
- kopirati:
vsebina: '{{komponenta | regex_replace ("-", "_")}} _ sklad: {{cf_result.stack_outputs | do_json}} '
dest: '{{tempfile_path}}. json'
no_log: res
spremenjeno_kdaj: napačno

- include_vars: '{{tempfile_path}}. json'

Posodabljanje skupine samodejnega skaliranja EC2

Spletno mesto ExpressVPN gostuje na več primerih EC2 v skupini samodejnega povečevanja za aplikacijo Balancer za nalaganje aplikacij, ki nam omogoča, da brez ustavljanja strežnikov uničimo strežnike, saj lahko uravnalnik obremenitve izteče obstoječe povezave, preden se instanca preneha.

Cloudformation orkestrira celotno obnovitev in sprožimo zgoraj opisano knjigo Ansible vsakih 24 ur, da obnovimo vse primere, pri čemer uporabimo atribut AutoScalingRollingUpdate UpdatePolicy za atribut AWS :: AutoScaling :: AutoScalingGroup vir.

Atribut UpdatePolicy se, kadar se preprosto večkrat sproži brez sprememb, ne uporablja - prikliče se le v posebnih okoliščinah, kot je opisano v dokumentaciji. Ena od teh okoliščin je posodobitev konfiguracije za zagon samodejnega skaliranja - predloga, ki jo skupina samodejnega skaliranja uporablja za zagon primerkov EC2 - ki vključuje skript uporabniških podatkov EC2, ki deluje pri ustvarjanju novega primerka:

vir 'AppLaunchConfiguration', vrsta: 'AWS :: AutoScaling: LaunchConfiguration',
Lastnosti: {
KeyName: param ("AppServerKey"),
ImageId: param ("AppServerAMI"),
InstanceType: param ('AppServerInstanceType'),
Varnostne skupine: [
param ('SecurityGroupApp'),
],
IamInstanceProfile: param ('ObnoviIamInstanceProfile'),
InstanceMonitoring: res,
BlockDeviceMappings: [
{
DeviceName: '/ dev / sda1', # korenski obseg
Ebs: {
VolumeSize: param ("AppServerStorageSize"),
VolumeType: param ("AppServerStorageType"),
DeleteOnTerminacija: res,
},
},
],
Uporabniški podatki: base64 (interpolate (datoteka ('skripte / app_user_data.sh'))),
}

Če posodobimo skript uporabniških podatkov, tudi pripombe, se bo štela, da bo konfiguracija zagona spremenjena, in Cloudformation bo posodobil vse primerke v skupini za samodejno skaliranje, da bodo skladni z novo konfiguracijo zagona..

Zahvaljujoč cloudformation-ruby-dsl in njegovi interpolatni uporabni funkciji lahko v skriptu app_user_data.sh uporabimo reference oblačenja:

readonly obnoviti_timestamp ="{{param ('RebuildTimestamp')}}"

Ta postopek zagotavlja, da je naša zagonska konfiguracija nova ob vsaki ponovni obnovi.

Kljuke za življenjski cikel

Uporabljamo kljuke v življenjskem ciklu samodejnega skaliranja, da zagotovimo, da so naši primerki v celoti pripravljeni in opravijo potrebne zdravstvene preglede, preden gredo v živo.

Uporaba kljuk v življenjskem ciklu nam omogoča, da imamo enak življenjski cikel primerka, ko sprožimo posodobitev z Cloudformation in ko se zgodi dogodek samodejnega skaliranja (na primer, ko primerek ne opravi zdravstvenega pregleda EC2 in se konča). Ne uporabljamo cfn-signala in pravilnika za posodabljanje samodejnega skaliranja WaitOnResourceSignals, ker se uporabljajo le, če Cloudformation sproži posodobitev.

Ko skupina za samodejno skaliranje ustvari nov primerek, se sproži kljuka življenjskega cikla EC2_INSTANCE_LAUNCHING, ki samodejno postavi primerek v stanje čakajočega: Počakajte.

Po tem, ko je primerek popolnoma konfiguriran, začne s pomočjo skripta uporabniških podatkov udarjati v lastne končne točke zdravstvenega preverjanja. Ko zdravstveni pregledi poročajo, da je aplikacija zdrava, izdamo NADALJEVANJE dejanja za ta kavelj življenjskega cikla, tako da se primerek pripne na izravnavo obremenitve in začne prikazovati promet.

Če zdravstveni pregledi ne uspejo, izdamo akcijo ABANDON, ki prekine napačno instanco, skupina za samodejno skaliranje pa sproži še eno.

Poleg tega, da ne opravi zdravstvenih pregledov, lahko skript uporabniških podatkov na drugih točkah ne uspe - na primer, če začasne težave s povezljivostjo preprečujejo namestitev programske opreme.

Želimo, da ustvarjanje novega primerka ne uspe takoj, ko spoznamo, da nikoli ne bo postalo zdravo. Da bi to dosegli, smo v skriptu uporabniških podatkov postavili past ERR skupaj z set -o errtrace, da pokliče funkcijo, ki pošlje dejanje življenjskega cikla ABANDON, tako da se lahko napačna instanca čim prej konča.

Skripti uporabniških podatkov

Skript uporabniških podatkov je odgovoren za namestitev vse potrebne programske opreme na primerek. Dolgo časa uspešno uporabljamo primere Ansible to Providation in Capistrano za uvajanje aplikacij, zato jih tudi tukaj uporabljamo, kar omogoča minimalno razliko med običajnimi napravami in obnovitvami.

Skripta uporabniških podatkov preveri naše skladišče aplikacij iz Github-a, ki vključuje skripte za zagotavljanje odgovorov, nato zažene Ansible in Capistrano je pokazal na localhost.

Pri preverjanju kode moramo biti prepričani, da je trenutno nameščena različica aplikacije med obnovitvijo. Skript uvajanja Capistrano vključuje nalogo, ki posodobi datoteko v S3, ki shrani trenutno nameščeno zavezo SHA. Ko se obnova zgodi, sistem poišče zagon, ki naj bi bil nameščen iz te datoteke.

Posodobitve programske opreme se uporabljajo z izvajanjem nadzorovane nadgradnje v ospredju z ukazom brez nadzora nadgradnje -d. Ko je končan, se primer ponovno zažene in začne zdravstveni pregled.

Soočanje s skrivnostmi

Strežnik potrebuje začasen dostop do skrivnosti (kot je geslo Ansible trezor), ki so bile pridobljene iz trgovine s parametri EC2. Med strežnikom do strežnika lahko kratek čas dostopate le kratek čas. Ko jih dobimo, takoj zamenjamo profil začetnega primerka z drugim, ki ima dostop samo do virov, ki so potrebni za zagon aplikacije.

Izogniti se želimo nobeni skrivnosti v trajnem pomnilniku primerka. Edina skrivnost, ki jo shranimo na disk, je Github SSH ključ, ne pa tudi njegova gesla. Tudi gesla za shranjevanje Ansible ne shranimo.

Vendar moramo te gesle posredovati SSH in Ansible, in to je mogoče le v interaktivnem načinu (tj. Pripomoček uporabnika poziva, da vnese gesle ročno) z dobrim razlogom - če je geslo del ukaza, je shranjeni v zgodovini lupine in so lahko vidni vsem uporabnikom v sistemu, če izvajajo ps. Uporabljamo program za pričakovanje za avtomatizacijo interakcije s temi orodji:

pričakovati << EOF
cd $ {repo_dir}
spawn make ansible_local env = $ {implemen_env} stack = $ {stack} ime gostitelja = $ {server_hostname}
nastavite čas 2
pričakujte »Geslo za trezor«
pošlji "$ {vault_password} \ r"
nastavite časovno omejitev 900
pričakovati {
"nedosegljivo = 0 neuspešno = 0" {
izhod 0
}
eof {
izhod 1
}
odmor {
izhod 1
}
}
EOF

Sprožitev obnove

Ker sprožimo obnovo z izvajanjem istega skripta Cloudformation, ki se uporablja za ustvarjanje / posodobitev naše infrastrukture, moramo poskrbeti, da ne bomo pomotoma posodobili dela infrastrukture, ki naj ne bi bil posodobljen med obnovo..

To dosežemo z nastavitvijo restriktivne politike nabora na naše skladbe Cloudformation, tako da se posodabljajo samo sredstva, potrebna za obnovo:

{
"Izjava" : [
{
"Učinek" : "Dovoli",
"Ukrep" : "Posodobitev: spremenite",
"Ravnatelj": "*",
"Vir" : [
"LogicalResourceId / * AutoScalingGroup"
]
},
{
"Učinek" : "Dovoli",
"Ukrep" : "Posodobitev: zamenjaj",
"Ravnatelj": "*",
"Vir" : [
"LogicalResourceId / * LaunchConfiguration"
]
}
]
}

Ko moramo opraviti dejanske posodobitve infrastrukture, moramo ročno posodobiti pravilnik za zlaganje, da omogočimo posodobitve teh virov izrecno.

Ker se naša gostiteljska imena in IP-ji spreminjajo vsak dan, imamo skript, ki posodablja naše lokalne zaloge Ansible in konfiguracije SSH. Z oznakami odkriva primere prek API-ja AWS, upodablja inventar in konfigurira datoteke iz predlogov ERB in doda nove IP-je v SSH unknown_hosts.

ExpressVPN sledi najvišjim varnostnim standardom

Obnova strežnikov nas ščiti pred posebno grožnjo: napadalci dobijo dostop do naših strežnikov prek ranljivosti jedra / programske opreme.

Vendar je to le eden od mnogih načinov, kako ohranjamo svojo infrastrukturo varno, vključno z, vendar ne omejeno na redne varnostne preglede in dostop do kritičnih sistemov, ki niso dostopni z interneta.

Poleg tega poskrbimo, da vsi naši kode in notranji procesi sledijo najvišjim varnostnim standardom.

Kako ExpressVPN ohranja svoje spletne strežnike zakrpane in varne
admin Author
Sorry! The Author has not filled his profile.