@@ -16,20 +16,21 @@ import (
1616 "github.com/uselagoon/lagoon-cli/internal/lagoon"
1717 "github.com/uselagoon/lagoon-cli/internal/lagoon/client"
1818 "github.com/uselagoon/lagoon-cli/pkg/output"
19+ "golang.org/x/oauth2"
1920 "gopkg.in/yaml.v3"
2021)
2122
2223// LagoonConfigFlags .
2324type LagoonConfigFlags struct {
24- Lagoon string `json:"lagoon,omitempty"`
25- Hostname string `json:"hostname,omitempty"`
26- Port string `json:"port,omitempty"`
27- GraphQL string `json:"graphql,omitempty"`
28- Token string `json:"token,omitempty"`
29- UI string `json:"ui ,omitempty"`
30- Kibana string `json:"kibana ,omitempty"`
31- SSHKey string `json:"sshkey ,omitempty"`
32- SSHPortal bool `json:"sshportal ,omitempty"`
25+ Lagoon string `json:"lagoon,omitempty"`
26+ Hostname string `json:"hostname,omitempty"`
27+ Port string `json:"port,omitempty"`
28+ GraphQL string `json:"graphql,omitempty"`
29+ Token string `json:"token,omitempty"`
30+ Grant * oauth2. Token `json:"grant ,omitempty"`
31+ UI string `json:"ui ,omitempty"`
32+ Kibana string `json:"kibana ,omitempty"`
33+ SSHKey string `json:"sshkey ,omitempty"`
3334}
3435
3536func parseLagoonConfig (flags pflag.FlagSet ) LagoonConfigFlags {
@@ -112,6 +113,7 @@ var configLagoonsCmd = &cobra.Command{
112113 if fullConfigList {
113114 mapData = append (mapData , returnNonEmptyString (lc .UI ))
114115 mapData = append (mapData , returnNonEmptyString (lc .Kibana ))
116+ mapData = append (mapData , returnNonEmptyString (lc .KeycloakURL ))
115117 }
116118 mapData = append (mapData , returnNonEmptyString (lc .SSHKey ))
117119 data = append (data , mapData )
@@ -129,6 +131,7 @@ var configLagoonsCmd = &cobra.Command{
129131 if fullConfigList {
130132 tableHeader = append (tableHeader , "UI-URL" )
131133 tableHeader = append (tableHeader , "Kibana-URL" )
134+ tableHeader = append (tableHeader , "Auth-URL" )
132135 }
133136 tableHeader = append (tableHeader , "SSH-Key" )
134137 output .RenderOutput (output.Table {
@@ -148,6 +151,18 @@ var configAddCmd = &cobra.Command{
148151 if lagoonConfig .Lagoon == "" {
149152 return fmt .Errorf ("Missing arguments: Lagoon name is not defined" )
150153 }
154+ sshToken , err := cmd .Flags ().GetBool ("ssh-token" )
155+ if err != nil {
156+ return err
157+ }
158+ keycloakURL , err := cmd .Flags ().GetString ("keycloak-url" )
159+ if err != nil {
160+ return err
161+ }
162+ keycloakIDP , err := cmd .Flags ().GetString ("keycloak-idp" )
163+ if err != nil {
164+ return err
165+ }
151166
152167 if lagoonConfig .Hostname != "" && lagoonConfig .Port != "" && lagoonConfig .GraphQL != "" {
153168 lc := lagoonCLIConfig .Lagoons [lagoonConfig .Lagoon ]
@@ -160,8 +175,19 @@ var configAddCmd = &cobra.Command{
160175 if lagoonConfig .Kibana != "" {
161176 lc .Kibana = lagoonConfig .Kibana
162177 }
178+ lc .Grant = & oauth2.Token {} //set up an empty grant
163179 if lagoonConfig .Token != "" {
164- lc .Token = lagoonConfig .Token
180+ // set the token into the grant, this is mainly for legacy based token backwards compatability
181+ // tokens added this way will be changed by the ssh or keycloak token generation process if they are not a legacy token
182+ lc .Grant .AccessToken = lagoonConfig .Token
183+ }
184+ lc .SSHToken = sshToken
185+ if keycloakURL != "" {
186+ // trim any trailing slashes from the keycloak url
187+ lc .KeycloakURL = strings .TrimRight (keycloakURL , "/" )
188+ }
189+ if keycloakIDP != "" {
190+ lc .KeycloakIDP = keycloakIDP
165191 }
166192 if lagoonConfig .SSHKey != "" {
167193 lc .SSHKey = lagoonConfig .SSHKey
@@ -178,6 +204,7 @@ var configAddCmd = &cobra.Command{
178204 "SSH-Port" ,
179205 "UI-URL" ,
180206 "Kibana-URL" ,
207+ "Keycloak-URL" ,
181208 "SSH-Key" ,
182209 },
183210 Data : []output.Data {
@@ -188,6 +215,7 @@ var configAddCmd = &cobra.Command{
188215 lagoonConfig .Port ,
189216 lagoonConfig .UI ,
190217 lagoonConfig .Kibana ,
218+ keycloakURL ,
191219 lagoonConfig .SSHKey ,
192220 },
193221 },
@@ -269,7 +297,7 @@ var configLagoonVersionCmd = &cobra.Command{
269297 current := lagoonCLIConfig .Current
270298 lc := client .New (
271299 lagoonCLIConfig .Lagoons [current ].GraphQL ,
272- lagoonCLIConfig .Lagoons [current ].Token ,
300+ lagoonCLIConfig .Lagoons [current ].Grant . AccessToken ,
273301 lagoonCLIConfig .Lagoons [current ].Version ,
274302 lagoonCLIVersion ,
275303 debug )
@@ -301,21 +329,32 @@ func init() {
301329 configCmd .AddCommand (configLagoonsCmd )
302330 configCmd .AddCommand (configLagoonVersionCmd )
303331 configAddCmd .Flags ().StringVarP (& lagoonHostname , "hostname" , "H" , "" ,
304- "Lagoon SSH hostname" )
332+ "Lagoon token endpoint hostname (eg, token.amazeeio.cloud) " )
305333 configAddCmd .Flags ().StringVarP (& lagoonPort , "port" , "P" , "" ,
306- "Lagoon SSH port" )
334+ "Lagoon token endpoint port (22) " )
307335 configAddCmd .Flags ().StringVarP (& lagoonGraphQL , "graphql" , "g" , "" ,
308- "Lagoon GraphQL endpoint" )
336+ "Lagoon GraphQL endpoint (eg, https://api.amazeeio.cloud/graphql) " )
309337 configAddCmd .Flags ().StringVarP (& lagoonToken , "token" , "t" , "" ,
310338 "Lagoon GraphQL token" )
311339 configAddCmd .Flags ().StringVarP (& lagoonUI , "ui" , "u" , "" ,
312- "Lagoon UI location (https://dashboard.amazeeio.cloud)" )
340+ "Optional: Lagoon UI location (eg, https://dashboard.amazeeio.cloud)" )
313341 configAddCmd .PersistentFlags ().BoolVarP (& createConfig , "create-config" , "" , false ,
314342 "Create the config file if it is non existent (to be used with --config-file)" )
315343 configAddCmd .Flags ().StringVarP (& lagoonKibana , "kibana" , "k" , "" ,
316- "Lagoon Kibana URL (https://logs.amazeeio.cloud)" )
344+ "Optional: Lagoon Kibana URL (eg, https://logs.amazeeio.cloud)" )
345+ configAddCmd .Flags ().StringP ("keycloak-url" , "K" , "" , `Lagoon Keycloak URL (eg, https://keycloak.amazeeio.cloud).
346+ Setting this will use keycloak for authentication instead of SSH based tokens.
347+ Set 'ssh-token=true' to override.
348+ Note: SSH keys are still required for SSH access.` )
349+ configAddCmd .Flags ().String ("keycloak-idp" , "" , `Optional: Lagoon Keycloak Identity Provider name.
350+ Set this to the name of the separate Identity Provider within keycloak if you use one.
351+ You may need to check with your Lagoon administrator if you use another SSO provider` )
317352 configAddCmd .Flags ().StringVarP (& lagoonSSHKey , "ssh-key" , "" , "" ,
318353 "SSH Key to use for this cluster for generating tokens" )
354+ configAddCmd .Flags ().Bool ("ssh-token" , true , `Set this context to only use ssh based tokens
355+ Set this to only use SSH based tokens if you're using the CLI in CI jobs or other automated processes
356+ where logging in via keycloak is not possible.
357+ This is enabled by default, it will be disabled by default in a future release.` )
319358 configLagoonsCmd .Flags ().BoolVarP (& fullConfigList , "show-full" , "" , false ,
320359 "Show full config output when listing Lagoon configurations" )
321360 configFeatureSwitch .Flags ().StringVarP (& updateCheck , "disable-update-check" , "" , "" ,
@@ -332,12 +371,14 @@ func readLagoonConfig(lc *lagoon.Config, file string) error {
332371 // configuration to point to the amazeeio lagoon instance
333372 if yesNo (fmt .Sprintf ("Config file '%s' does not exist, do you want to create it with defaults?" , file )) {
334373 l := lagoon.Context {
335- GraphQL : "https://api.lagoon.amazeeio.cloud/graphql" ,
336- HostName : "ssh.lagoon.amazeeio.cloud" ,
337- Token : "" ,
338- Port : "32222" ,
339- UI : "https://dashboard.amazeeio.cloud" ,
340- Kibana : "https://logs.amazeeio.cloud/" ,
374+ GraphQL : "https://api.amazeeio.cloud/graphql" ,
375+ HostName : "token.amazeeio.cloud" ,
376+ Grant : & oauth2.Token {}, // set an empty oauth token
377+ Port : "22" ,
378+ UI : "https://dashboard.amazeeio.cloud" ,
379+ Kibana : "https://logs.amazeeio.cloud/" ,
380+ KeycloakURL : "https://keycloak.amazeeio.cloud/" ,
381+ SSHToken : true , //@TODO: retain ssh token generation by default, eventually change this to false so that token generation is opt-in
341382 }
342383 lc .Lagoons = map [string ]lagoon.Context {}
343384 lc .Lagoons ["amazeeio" ] = l
@@ -354,6 +395,20 @@ func readLagoonConfig(lc *lagoon.Config, file string) error {
354395 if l .GraphQL == "" || l .HostName == "" || l .Port == "" {
355396 return fmt .Errorf ("configured lagoon %s is missing required configuration for graphql, hostname, or port" , ln )
356397 }
398+ if l .Token != "" {
399+ // if there isn't already a grant in the config
400+ if lc .Lagoons [ln ].Grant == nil {
401+ // create one by just setting the token to be the grants accesstoken. This allows legacy tokens still still function
402+ grant := & oauth2.Token {
403+ AccessToken : l .Token ,
404+ }
405+ d := lc .Lagoons [ln ]
406+ d .Grant = grant
407+ // retain the `token` field for now for backwards compatability with older cli versions
408+ // d.Token = ""
409+ lc .Lagoons [ln ] = d
410+ }
411+ }
357412 }
358413 return nil
359414
0 commit comments