PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/saltstack/salt/lib/python3.10/site-packages/salt/modules
Viewing File: /opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/boto_secgroup.py
""" Connection module for Amazon Security Groups .. versionadded:: 2014.7.0 :configuration: This module accepts explicit ec2 credentials but can also utilize IAM roles assigned to the instance through Instance Profiles. Dynamic credentials are then automatically obtained from AWS API and no further configuration is necessary. More Information available at: .. code-block:: text http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html If IAM roles are not used you need to specify them either in a pillar or in the minion's config file: .. code-block:: yaml secgroup.keyid: GKTADJGHEIQSXMKKRBJ08H secgroup.key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs A region may also be specified in the configuration: .. code-block:: yaml secgroup.region: us-east-1 If a region is not specified, the default is us-east-1. It's also possible to specify key, keyid and region via a profile, either as a passed in dict, or as a string to pull from pillars or minion config: .. code-block:: yaml myprofile: keyid: GKTADJGHEIQSXMKKRBJ08H key: askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs region: us-east-1 :depends: boto """ # keep lint from choking on _get_conn and _cache_id # pylint: disable=E0602 import logging import salt.utils.odict as odict import salt.utils.versions from salt.exceptions import CommandExecutionError, SaltInvocationError log = logging.getLogger(__name__) try: # pylint: disable=unused-import import boto import boto.ec2 # pylint: enable=unused-import logging.getLogger("boto").setLevel(logging.CRITICAL) HAS_BOTO = True except ImportError: HAS_BOTO = False def __virtual__(): """ Only load if boto libraries exist and if boto libraries are greater than a given version. """ # Boto < 2.4.0 GroupOrCIDR objects have different attributes than # Boto >= 2.4.0 GroupOrCIDR objects # Differences include no group_id attribute in Boto < 2.4.0 and returning # a groupId attribute when a GroupOrCIDR object authorizes an IP range # Support for Boto < 2.4.0 can be added if needed has_boto_reqs = salt.utils.versions.check_boto_reqs( boto_ver="2.4.0", check_boto3=False ) if has_boto_reqs is True: __utils__["boto.assign_funcs"](__name__, "ec2", pack=__salt__) return has_boto_reqs def exists( name=None, region=None, key=None, keyid=None, profile=None, vpc_id=None, vpc_name=None, group_id=None, ): """ Check to see if a security group exists. CLI Example: .. code-block:: bash salt myminion boto_secgroup.exists mysecgroup """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) group = _get_group( conn, name=name, vpc_id=vpc_id, vpc_name=vpc_name, group_id=group_id, region=region, key=key, keyid=keyid, profile=profile, ) if group: return True else: return False def _vpc_name_to_id( vpc_id=None, vpc_name=None, region=None, key=None, keyid=None, profile=None ): data = __salt__["boto_vpc.get_id"]( name=vpc_name, region=region, key=key, keyid=keyid, profile=profile ) return data.get("id") def _split_rules(rules): """ Split rules with combined grants into individual rules. Amazon returns a set of rules with the same protocol, from and to ports together as a single rule with a set of grants. Authorizing and revoking rules, however, is done as a split set of rules. This function splits the rules up. """ split = [] for rule in rules: ip_protocol = rule.get("ip_protocol") to_port = rule.get("to_port") from_port = rule.get("from_port") grants = rule.get("grants") for grant in grants: _rule = { "ip_protocol": ip_protocol, "to_port": to_port, "from_port": from_port, } for key, val in grant.items(): _rule[key] = val split.append(_rule) return split def _get_group( conn=None, name=None, vpc_id=None, vpc_name=None, group_id=None, region=None, key=None, keyid=None, profile=None, ): # pylint: disable=W0613 """ Get a group object given a name, name and vpc_id/vpc_name or group_id. Return a boto.ec2.securitygroup.SecurityGroup object if the group is found, else return None. """ if vpc_name and vpc_id: raise SaltInvocationError( "The params 'vpc_id' and 'vpc_name' are mutually exclusive." ) if vpc_name: try: vpc_id = _vpc_name_to_id( vpc_id=vpc_id, vpc_name=vpc_name, region=region, key=key, keyid=keyid, profile=profile, ) except boto.exception.BotoServerError as e: log.debug(e) return None if name: if vpc_id is None: log.debug("getting group for %s", name) group_filter = {"group-name": name} filtered_groups = conn.get_all_security_groups(filters=group_filter) # security groups can have the same name if groups exist in both # EC2-Classic and EC2-VPC # iterate through groups to ensure we return the EC2-Classic # security group for group in filtered_groups: # a group in EC2-Classic will have vpc_id set to None if group.vpc_id is None: return group # If there are more security groups, and no vpc_id, we can't know which one to choose. if len(filtered_groups) > 1: raise CommandExecutionError( "Security group belongs to more VPCs, specify the VPC ID!" ) elif len(filtered_groups) == 1: return filtered_groups[0] return None elif vpc_id: log.debug("getting group for %s in vpc_id %s", name, vpc_id) group_filter = {"group-name": name, "vpc_id": vpc_id} filtered_groups = conn.get_all_security_groups(filters=group_filter) if len(filtered_groups) == 1: return filtered_groups[0] else: return None else: return None elif group_id: try: groups = conn.get_all_security_groups(group_ids=[group_id]) except boto.exception.BotoServerError as e: log.debug(e) return None if len(groups) == 1: return groups[0] else: return None else: return None def _parse_rules(sg, rules): _rules = [] for rule in rules: log.debug("examining rule %s for group %s", rule, sg.id) attrs = ["ip_protocol", "from_port", "to_port", "grants"] _rule = odict.OrderedDict() for attr in attrs: val = getattr(rule, attr) if not val: continue if attr == "grants": _grants = [] for grant in val: log.debug("examining grant %s for", grant) g_attrs = { "name": "source_group_name", "owner_id": "source_group_owner_id", "group_id": "source_group_group_id", "cidr_ip": "cidr_ip", } _grant = odict.OrderedDict() for g_attr, g_attr_map in g_attrs.items(): g_val = getattr(grant, g_attr) if not g_val: continue _grant[g_attr_map] = g_val _grants.append(_grant) _rule["grants"] = _grants elif attr == "from_port": _rule[attr] = int(val) elif attr == "to_port": _rule[attr] = int(val) else: _rule[attr] = val _rules.append(_rule) return _rules def get_all_security_groups( groupnames=None, group_ids=None, filters=None, region=None, key=None, keyid=None, profile=None, ): """ Return a list of all Security Groups matching the given criteria and filters. Note that the ``groupnames`` argument only functions correctly for EC2 Classic and default VPC Security Groups. To find groups by name in other VPCs you'll want to use the ``group-name`` filter instead. The valid keys for the ``filters`` argument can be found in `AWS's API documentation <https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html>`_. CLI Example: .. code-block:: bash salt myminion boto_secgroup.get_all_security_groups filters='{group-name: mygroup}' """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if isinstance(groupnames, str): groupnames = [groupnames] if isinstance(group_ids, str): groupnames = [group_ids] interesting = [ "description", "id", "instances", "name", "owner_id", "region", "rules", "rules_egress", "tags", "vpc_id", ] ret = [] try: r = conn.get_all_security_groups( groupnames=groupnames, group_ids=group_ids, filters=filters ) for g in r: n = {} for a in interesting: v = getattr(g, a, None) if a == "region": v = v.name elif a in ("rules", "rules_egress"): v = _parse_rules(g, v) elif a == "instances": v = [i.id for i in v()] n[a] = v ret += [n] return ret except boto.exception.BotoServerError as e: log.debug(e) return [] def get_group_id( name, vpc_id=None, vpc_name=None, region=None, key=None, keyid=None, profile=None ): """ Get a Group ID given a Group Name or Group Name and VPC ID CLI Example: .. code-block:: bash salt myminion boto_secgroup.get_group_id mysecgroup """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if name.startswith("sg-"): log.debug("group %s is a group id. get_group_id not called.", name) return name group = _get_group( conn=conn, name=name, vpc_id=vpc_id, vpc_name=vpc_name, region=region, key=key, keyid=keyid, profile=profile, ) return getattr(group, "id", None) def convert_to_group_ids( groups, vpc_id=None, vpc_name=None, region=None, key=None, keyid=None, profile=None ): """ Given a list of security groups and a vpc_id, convert_to_group_ids will convert all list items in the given list to security group ids. CLI Example: .. code-block:: bash salt myminion boto_secgroup.convert_to_group_ids mysecgroup vpc-89yhh7h """ log.debug("security group contents %s pre-conversion", groups) group_ids = [] for group in groups: group_id = get_group_id( name=group, vpc_id=vpc_id, vpc_name=vpc_name, region=region, key=key, keyid=keyid, profile=profile, ) if not group_id: # Security groups are a big deal - need to fail if any can't be resolved... # But... if we're running in test mode, it may just be that the SG is scheduled # to be created, and thus WOULD have been there if running "for real"... if __opts__["test"]: log.warning( "Security Group `%s` could not be resolved to an ID. This may " "cause a failure when not running in test mode.", group, ) return [] else: raise CommandExecutionError( "Could not resolve Security Group name {} to a Group ID".format( group ) ) else: group_ids.append(str(group_id)) log.debug("security group contents %s post-conversion", group_ids) return group_ids def get_config( name=None, group_id=None, region=None, key=None, keyid=None, profile=None, vpc_id=None, vpc_name=None, ): """ Get the configuration for a security group. CLI Example: .. code-block:: bash salt myminion boto_secgroup.get_config mysecgroup """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) sg = _get_group( conn, name=name, vpc_id=vpc_id, vpc_name=vpc_name, group_id=group_id, region=region, key=key, keyid=keyid, profile=profile, ) if sg: ret = odict.OrderedDict() ret["name"] = sg.name # TODO: add support for vpc_id in return # ret['vpc_id'] = sg.vpc_id ret["group_id"] = sg.id ret["owner_id"] = sg.owner_id ret["description"] = sg.description ret["tags"] = sg.tags _rules = _parse_rules(sg, sg.rules) _rules_egress = _parse_rules(sg, sg.rules_egress) ret["rules"] = _split_rules(_rules) ret["rules_egress"] = _split_rules(_rules_egress) return ret else: return None def create( name, description, vpc_id=None, vpc_name=None, region=None, key=None, keyid=None, profile=None, ): """ Create a security group. CLI Example: .. code-block:: bash salt myminion boto_secgroup.create mysecgroup 'My Security Group' """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) if not vpc_id and vpc_name: try: vpc_id = _vpc_name_to_id( vpc_id=vpc_id, vpc_name=vpc_name, region=region, key=key, keyid=keyid, profile=profile, ) except boto.exception.BotoServerError as e: log.debug(e) return False created = conn.create_security_group(name, description, vpc_id) if created: log.info("Created security group %s.", name) return True else: msg = f"Failed to create security group {name}." log.error(msg) return False def delete( name=None, group_id=None, region=None, key=None, keyid=None, profile=None, vpc_id=None, vpc_name=None, ): """ Delete a security group. CLI Example: .. code-block:: bash salt myminion boto_secgroup.delete mysecgroup """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) group = _get_group( conn, name=name, vpc_id=vpc_id, vpc_name=vpc_name, group_id=group_id, region=region, key=key, keyid=keyid, profile=profile, ) if group: deleted = conn.delete_security_group(group_id=group.id) if deleted: log.info("Deleted security group %s with id %s.", group.name, group.id) return True else: msg = f"Failed to delete security group {name}." log.error(msg) return False else: log.debug("Security group not found.") return False def authorize( name=None, source_group_name=None, source_group_owner_id=None, ip_protocol=None, from_port=None, to_port=None, cidr_ip=None, group_id=None, source_group_group_id=None, region=None, key=None, keyid=None, profile=None, vpc_id=None, vpc_name=None, egress=False, ): """ Add a new rule to an existing security group. CLI Example: .. code-block:: bash salt myminion boto_secgroup.authorize mysecgroup ip_protocol=tcp from_port=80 to_port=80 cidr_ip='['10.0.0.0/8', '192.168.0.0/24']' """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) group = _get_group( conn, name=name, vpc_id=vpc_id, vpc_name=vpc_name, group_id=group_id, region=region, key=key, keyid=keyid, profile=profile, ) if group: try: added = None if not egress: added = conn.authorize_security_group( src_security_group_name=source_group_name, src_security_group_owner_id=source_group_owner_id, ip_protocol=ip_protocol, from_port=from_port, to_port=to_port, cidr_ip=cidr_ip, group_id=group.id, src_security_group_group_id=source_group_group_id, ) else: added = conn.authorize_security_group_egress( ip_protocol=ip_protocol, from_port=from_port, to_port=to_port, cidr_ip=cidr_ip, group_id=group.id, src_group_id=source_group_group_id, ) if added: log.info( "Added rule to security group %s with id %s", group.name, group.id ) return True else: msg = "Failed to add rule to security group {} with id {}.".format( group.name, group.id ) log.error(msg) return False except boto.exception.EC2ResponseError as e: # if we are trying to add the same rule then we are already in the desired state, return true if e.error_code == "InvalidPermission.Duplicate": return True msg = "Failed to add rule to security group {} with id {}.".format( group.name, group.id ) log.error(msg) log.error(e) return False else: log.error("Failed to add rule to security group.") return False def revoke( name=None, source_group_name=None, source_group_owner_id=None, ip_protocol=None, from_port=None, to_port=None, cidr_ip=None, group_id=None, source_group_group_id=None, region=None, key=None, keyid=None, profile=None, vpc_id=None, vpc_name=None, egress=False, ): """ Remove a rule from an existing security group. CLI Example: .. code-block:: bash salt myminion boto_secgroup.revoke mysecgroup ip_protocol=tcp from_port=80 to_port=80 cidr_ip='10.0.0.0/8' """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) group = _get_group( conn, name=name, vpc_id=vpc_id, vpc_name=vpc_name, group_id=group_id, region=region, key=key, keyid=keyid, profile=profile, ) if group: try: revoked = None if not egress: revoked = conn.revoke_security_group( src_security_group_name=source_group_name, src_security_group_owner_id=source_group_owner_id, ip_protocol=ip_protocol, from_port=from_port, to_port=to_port, cidr_ip=cidr_ip, group_id=group.id, src_security_group_group_id=source_group_group_id, ) else: revoked = conn.revoke_security_group_egress( ip_protocol=ip_protocol, from_port=from_port, to_port=to_port, cidr_ip=cidr_ip, group_id=group.id, src_group_id=source_group_group_id, ) if revoked: log.info( "Removed rule from security group %s with id %s.", group.name, group.id, ) return True else: msg = "Failed to remove rule from security group {} with id {}.".format( group.name, group.id ) log.error(msg) return False except boto.exception.EC2ResponseError as e: msg = "Failed to remove rule from security group {} with id {}.".format( group.name, group.id ) log.error(msg) log.error(e) return False else: log.error("Failed to remove rule from security group.") return False def _find_vpcs( vpc_id=None, vpc_name=None, cidr=None, tags=None, region=None, key=None, keyid=None, profile=None, ): """ Given VPC properties, find and return matching VPC ids. Borrowed from boto_vpc; these could be refactored into a common library """ if all((vpc_id, vpc_name)): raise SaltInvocationError("Only one of vpc_name or vpc_id may be provided.") if not any((vpc_id, vpc_name, tags, cidr)): raise SaltInvocationError( "At least one of the following must be " "provided: vpc_id, vpc_name, cidr or tags." ) local_get_conn = __utils__["boto.get_connection_func"]("vpc") conn = local_get_conn(region=region, key=key, keyid=keyid, profile=profile) filter_parameters = {"filters": {}} if vpc_id: filter_parameters["vpc_ids"] = [vpc_id] if cidr: filter_parameters["filters"]["cidr"] = cidr if vpc_name: filter_parameters["filters"]["tag:Name"] = vpc_name if tags: for tag_name, tag_value in tags.items(): filter_parameters["filters"][f"tag:{tag_name}"] = tag_value vpcs = conn.get_all_vpcs(**filter_parameters) log.debug( "The filters criteria %s matched the following VPCs:%s", filter_parameters, vpcs ) if vpcs: return [vpc.id for vpc in vpcs] else: return [] def set_tags( tags, name=None, group_id=None, vpc_name=None, vpc_id=None, region=None, key=None, keyid=None, profile=None, ): """ Sets tags on a security group. .. versionadded:: 2016.3.0 tags a dict of key:value pair of tags to set on the security group name the name of the security group group_id the group id of the security group (in lie of a name/vpc combo) vpc_name the name of the vpc to search the named group for vpc_id the id of the vpc, in lieu of the vpc_name region the amazon region key amazon key keyid amazon keyid profile amazon profile CLI Example: .. code-block:: bash salt myminion boto_secgroup.set_tags "{'TAG1': 'Value1', 'TAG2': 'Value2'}" security_group_name vpc_id=vpc-13435 profile=my_aws_profile """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) secgrp = _get_group( conn, name=name, vpc_id=vpc_id, vpc_name=vpc_name, group_id=group_id, region=region, key=key, keyid=keyid, profile=profile, ) if secgrp: if isinstance(tags, dict): secgrp.add_tags(tags) else: msg = "Tags must be a dict of tagname:tagvalue" raise SaltInvocationError(msg) else: msg = "The security group could not be found" raise SaltInvocationError(msg) return True def delete_tags( tags, name=None, group_id=None, vpc_name=None, vpc_id=None, region=None, key=None, keyid=None, profile=None, ): """ Deletes tags from a security group. .. versionadded:: 2016.3.0 tags a list of tags to remove name the name of the security group group_id the group id of the security group (in lie of a name/vpc combo) vpc_name the name of the vpc to search the named group for vpc_id the id of the vpc, in lieu of the vpc_name region the amazon region key amazon key keyid amazon keyid profile amazon profile CLI Example: .. code-block:: bash salt myminion boto_secgroup.delete_tags ['TAG_TO_DELETE1','TAG_TO_DELETE2'] security_group_name vpc_id=vpc-13435 profile=my_aws_profile """ conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) secgrp = _get_group( conn, name=name, vpc_id=vpc_id, vpc_name=vpc_name, group_id=group_id, region=region, key=key, keyid=keyid, profile=profile, ) if secgrp: if isinstance(tags, list): tags_to_remove = {} for tag in tags: tags_to_remove[tag] = None secgrp.remove_tags(tags_to_remove) else: msg = "Tags must be a list of tagnames to remove from the security group" raise SaltInvocationError(msg) else: msg = "The security group could not be found" raise SaltInvocationError(msg) return True