99 "regexp"
1010 "strings"
1111
12+ "github.com/cloudflare/cloudflare-go"
1213 log "github.com/sirupsen/logrus"
1314 "golang.org/x/crypto/ssh/terminal"
1415
@@ -64,6 +65,8 @@ var addCmd = &cobra.Command{
6465 },
6566 Run : func (cmd * cobra.Command , args []string ) {
6667 profileName := strings .TrimSpace (args [0 ])
68+ sessionDuration , _ := cmd .Flags ().GetString ("session-duration" )
69+ profileTemplate , _ := cmd .Flags ().GetString ("profile-template" )
6770
6871 reader := bufio .NewReader (os .Stdin )
6972 fmt .Print ("Email address: " )
@@ -73,13 +76,14 @@ var addCmd = &cobra.Command{
7376 fmt .Print ("Authentication value (API key or API token): " )
7477 byteAuthValue , err := terminal .ReadPassword (0 )
7578 if err != nil {
76- log .Fatalf ( " \n unable to read authentication value: %s " , err )
79+ log .Fatal ( "unable to read authentication value: " , err )
7780 }
7881 authValue := string (byteAuthValue )
82+ fmt .Println ()
7983
8084 authType , err := determineAuthType (strings .TrimSpace (authValue ))
8185 if err != nil {
82- log .Fatalf ("failed to detect authentication type: %s " , err )
86+ log .Fatal ("failed to detect authentication type: " , err )
8387 }
8488
8589 home , err := homedir .Dir ()
@@ -109,14 +113,55 @@ var addCmd = &cobra.Command{
109113 tomlConfigStruct .Profiles = make (map [string ]profile )
110114 }
111115
112- tomlConfigStruct . Profiles [ profileName ] = profile {
116+ newProfile : = profile {
113117 Email : emailAddress ,
114118 AuthType : authType ,
115119 }
116120
121+ if sessionDuration != "" {
122+ newProfile .SessionDuration = sessionDuration
123+ } else {
124+ log .Debug ("session-duration was not set, not using short lived tokens" )
125+ }
126+
127+ var api * cloudflare.API
128+ if authType == "api_token" {
129+ api , err = cloudflare .NewWithAPIToken (authValue )
130+ if err != nil {
131+ log .Fatal (err )
132+ }
133+ } else {
134+ api , err = cloudflare .New (authValue , emailAddress )
135+ if err != nil {
136+ log .Fatal (err )
137+ }
138+ }
139+
140+ if profileTemplate != "" {
141+ // The policies require that one of the resources is the current user.
142+ // This leads to a potential chicken/egg scenario where the user doesn't
143+ // valid credentials but needs them to generate the resources. We
144+ // intentionally spit out `Debug` and `Fatal` messages here to show the
145+ // original error *and* the friendly version of how to resolve it.
146+ userDetails , err := api .UserDetails ()
147+ if err != nil {
148+ log .Debug (err )
149+ log .Fatal ("failed to fetch user ID from the Cloudflare API which is required to generate the predefined short lived token policies. If you are using API tokens, please allow the permission to access your user details and try again." )
150+ }
151+
152+ generatedPolicy , err := generatePolicy (profileTemplate , userDetails .ID )
153+ if err != nil {
154+ log .Fatal (err )
155+ }
156+ newProfile .Policies = generatedPolicy
157+ }
158+
159+ log .Debugf ("new profile: %+v" , newProfile )
160+ tomlConfigStruct .Profiles [profileName ] = newProfile
161+
117162 configFile , err := os .OpenFile (home + defaultFullConfigPath , os .O_RDWR | os .O_CREATE | os .O_TRUNC , 0700 )
118163 if err != nil {
119- log .Fatalf ("failed to open file at %s " , home + defaultFullConfigPath )
164+ log .Fatal ("failed to open file at " , home + defaultFullConfigPath )
120165 }
121166 defer configFile .Close ()
122167 if err := toml .NewEncoder (configFile ).Encode (tomlConfigStruct ); err != nil {
@@ -145,3 +190,129 @@ func determineAuthType(s string) (string, error) {
145190 return "" , errors .New ("invalid API token or API key format" )
146191 }
147192}
193+
194+ func generatePolicy (policyType , userID string ) ([]policy , error ) {
195+ readOnlyPolicy := []policy {
196+ {
197+ Effect : "allow" ,
198+ Resources : map [string ]interface {}{"com.cloudflare.api.account.*" : "*" },
199+ PermissionGroups : []permissionGroup {
200+ {ID : "7ea222f6d5064cfa89ea366d7c1fee89" },
201+ {ID : "b05b28e839c54467a7d6cba5d3abb5a3" },
202+ {ID : "4f3196a5c95747b6ad82e34e1d0a694f" },
203+ {ID : "0f4841f80adb4bada5a09493300e7f8d" },
204+ {ID : "26bc23f853634eb4bff59983b9064fde" },
205+ {ID : "91f7ce32fa614d73b7e1fc8f0e78582b" },
206+ {ID : "b89a480218d04ceb98b4fe57ca29dc1f" },
207+ {ID : "de7a688cc47d43bd9ea700b467a09c96" },
208+ {ID : "4f1071168de8466e9808de86febfc516" },
209+ {ID : "c1fde68c7bcc44588cbb6ddbc16d6480" },
210+ {ID : "efea2ab8357b47888938f101ae5e053f" },
211+ {ID : "7cf72faf220841aabcfdfab81c43c4f6" },
212+ {ID : "5f48a472240a4b489a21d43bd19a06e1" },
213+ {ID : "e763fae6ee95443b8f56f19213c5f2a5" },
214+ {ID : "9d24387c6e8544e2bc4024a03991339f" },
215+ {ID : "6a315a56f18441e59ed03352369ae956" },
216+ {ID : "58abbad6d2ce40abb2594fbe932a2e0e" },
217+ {ID : "de21485a24744b76a004aa153898f7fe" },
218+ {ID : "3f376c8e6f764a938b848bd01c8995c4" },
219+ {ID : "8b47d2786a534c08a1f94ee8f9f599ef" },
220+ {ID : "1a71c399035b4950a1bd1466bbe4f420" },
221+ {ID : "05880cd1bdc24d8bae0be2136972816b" },
222+ },
223+ },
224+ {
225+ Effect : "allow" ,
226+ Resources : map [string ]interface {}{"com.cloudflare.api.account.zone.*" : "*" },
227+ PermissionGroups : []permissionGroup {
228+ {ID : "eb258a38ea634c86a0c89da6b27cb6b6" },
229+ {ID : "9c88f9c5bce24ce7af9a958ba9c504db" },
230+ {ID : "82e64a83756745bbbb1c9c2701bf816b" },
231+ {ID : "4ec32dfcb35641c5bb32d5ef1ab963b4" },
232+ {ID : "e9a975f628014f1d85b723993116f7d5" },
233+ {ID : "c4a30cd58c5d42619c86a3c36c441e2d" },
234+ {ID : "b415b70a4fd1412886f164451f20405c" },
235+ {ID : "7b7216b327b04b8fbc8f524e1f9b7531" },
236+ {ID : "2072033d694d415a936eaeb94e6405b8" },
237+ {ID : "c8fed203ed3043cba015a93ad1616f1f" },
238+ {ID : "517b21aee92c4d89936c976ba6e4be55" },
239+ },
240+ },
241+ {
242+ Effect : "allow" ,
243+ Resources : map [string ]interface {}{"com.cloudflare.api.user." + userID : "*" },
244+ PermissionGroups : []permissionGroup {
245+ {ID : "3518d0f75557482e952c6762d3e64903" },
246+ {ID : "8acbe5bb0d54464ab867149d7f7cf8ac" },
247+ },
248+ },
249+ }
250+
251+ writeEverythingPolicy := []policy {
252+ {
253+ Effect : "allow" ,
254+ Resources : map [string ]interface {}{"com.cloudflare.api.account.*" : "*" },
255+ PermissionGroups : []permissionGroup {
256+ {ID : "1e13c5124ca64b72b1969a67e8829049" },
257+ {ID : "b05b28e839c54467a7d6cba5d3abb5a3" },
258+ {ID : "29d3afbfd4054af9accdd1118815ed05" },
259+ {ID : "2fc1072ee6b743828db668fcb3f9dee7" },
260+ {ID : "bfe0d8686a584fa680f4c53b5eb0de6d" },
261+ {ID : "a1c0fec57cf94af79479a6d827fa518c" },
262+ {ID : "b89a480218d04ceb98b4fe57ca29dc1f" },
263+ {ID : "a416acf9ef5a4af19fb11ed3b96b1fe6" },
264+ {ID : "2edbf20661fd4661b0fe10e9e12f485c" },
265+ {ID : "1af1fa2adc104452b74a9a3364202f20" },
266+ {ID : "c07321b023e944ff818fec44d8203567" },
267+ {ID : "6c80e02421494afc9ae14414ed442632" },
268+ {ID : "da6d2d6f2ec8442eaadda60d13f42bca" },
269+ {ID : "2ae23e4939d54074b7d252d27ce75a77" },
270+ {ID : "d2a1802cc9a34e30852f8b33869b2f3c" },
271+ {ID : "96163bd1b0784f62b3e44ed8c2ab1eb6" },
272+ {ID : "61ddc58f1da14f95b33b41213360cbeb" },
273+ {ID : "b33f02c6f7284e05a6f20741c0bb0567" },
274+ {ID : "f7f0eda5697f475c90846e879bab8666" },
275+ {ID : "e086da7e2179491d91ee5f35b3ca210a" },
276+ {ID : "05880cd1bdc24d8bae0be2136972816b" },
277+ },
278+ },
279+ {
280+ Effect : "allow" ,
281+ Resources : map [string ]interface {}{"com.cloudflare.api.account.zone.*" : "*" },
282+ PermissionGroups : []permissionGroup {
283+ {ID : "959972745952452f8be2452be8cbb9f2" },
284+ {ID : "9c88f9c5bce24ce7af9a958ba9c504db" },
285+ {ID : "094547ab6e77498c8c4dfa87fadd5c51" },
286+ {ID : "e17beae8b8cb423a99b1730f21238bed" },
287+ {ID : "4755a26eedb94da69e1066d98aa820be" },
288+ {ID : "43137f8d07884d3198dc0ee77ca6e79b" },
289+ {ID : "6d7f2f5f5b1d4a0e9081fdc98d432fd1" },
290+ {ID : "3e0b5820118e47f3922f7c989e673882" },
291+ {ID : "ed07f6c337da4195b4e72a1fb2c6bcae" },
292+ {ID : "c03055bc037c4ea9afb9a9f104b7b721" },
293+ {ID : "28f4b596e7d643029c524985477ae49a" },
294+ {ID : "e6d2666161e84845a636613608cee8d5" },
295+ {ID : "3030687196b94b638145a3953da2b699" },
296+ },
297+ },
298+ {
299+ Effect : "allow" ,
300+ Resources : map [string ]interface {}{"com.cloudflare.api.user." + userID : "*" },
301+ PermissionGroups : []permissionGroup {
302+ {ID : "9201bc6f42d440968aaab0c6f17ebb1d" },
303+ {ID : "55a5e17cc99e4a3fa1f3432d262f2e55" },
304+ },
305+ },
306+ }
307+
308+ switch policyType {
309+ case "write-everything" :
310+ log .Debug ("configuring a write-everything template" )
311+ return writeEverythingPolicy , nil
312+ case "read-only" :
313+ log .Debug ("configuring a read-only template" )
314+ return readOnlyPolicy , nil
315+ }
316+
317+ return nil , fmt .Errorf ("unable to generate policy for %q" , policyType )
318+ }
0 commit comments