Skip to content

Commit 8da86fe

Browse files
committed
feat: support keycloak based logins in the cli
1 parent 916ff8c commit 8da86fe

32 files changed

+308
-173
lines changed

cmd/config.go

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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 .
2324
type 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

3536
func 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

cmd/deploy.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use 'lagoon deploy latest' instead`,
5050
current := lagoonCLIConfig.Current
5151
lc := client.New(
5252
lagoonCLIConfig.Lagoons[current].GraphQL,
53-
lagoonCLIConfig.Lagoons[current].Token,
53+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
5454
lagoonCLIConfig.Lagoons[current].Version,
5555
lagoonCLIVersion,
5656
debug)
@@ -104,7 +104,7 @@ var deployPromoteCmd = &cobra.Command{
104104
current := lagoonCLIConfig.Current
105105
lc := client.New(
106106
lagoonCLIConfig.Lagoons[current].GraphQL,
107-
lagoonCLIConfig.Lagoons[current].Token,
107+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
108108
lagoonCLIConfig.Lagoons[current].Version,
109109
lagoonCLIVersion,
110110
debug)
@@ -150,7 +150,7 @@ This environment should already exist in lagoon. It is analogous with the 'Deplo
150150
current := lagoonCLIConfig.Current
151151
lc := client.New(
152152
lagoonCLIConfig.Lagoons[current].GraphQL,
153-
lagoonCLIConfig.Lagoons[current].Token,
153+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
154154
lagoonCLIConfig.Lagoons[current].Version,
155155
lagoonCLIVersion,
156156
debug)
@@ -219,7 +219,7 @@ This pullrequest may not already exist as an environment in lagoon.`,
219219
current := lagoonCLIConfig.Current
220220
lc := client.New(
221221
lagoonCLIConfig.Lagoons[current].GraphQL,
222-
lagoonCLIConfig.Lagoons[current].Token,
222+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
223223
lagoonCLIConfig.Lagoons[current].Version,
224224
lagoonCLIVersion,
225225
debug)

cmd/deploytarget.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package cmd
33
import (
44
"context"
55
"fmt"
6+
"strconv"
7+
68
"github.com/spf13/cobra"
79
"github.com/uselagoon/lagoon-cli/internal/lagoon"
810
"github.com/uselagoon/lagoon-cli/internal/lagoon/client"
@@ -11,7 +13,6 @@ import (
1113
l "github.com/uselagoon/machinery/api/lagoon"
1214
lclient "github.com/uselagoon/machinery/api/lagoon/client"
1315
s "github.com/uselagoon/machinery/api/schema"
14-
"strconv"
1516
)
1617

1718
var addDeployTargetCmd = &cobra.Command{
@@ -100,7 +101,7 @@ var addDeployTargetCmd = &cobra.Command{
100101
current := lagoonCLIConfig.Current
101102
lc := client.New(
102103
lagoonCLIConfig.Lagoons[current].GraphQL,
103-
lagoonCLIConfig.Lagoons[current].Token,
104+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
104105
lagoonCLIConfig.Lagoons[current].Version,
105106
lagoonCLIVersion,
106107
debug)
@@ -212,7 +213,7 @@ var updateDeployTargetCmd = &cobra.Command{
212213
current := lagoonCLIConfig.Current
213214
lc := client.New(
214215
lagoonCLIConfig.Lagoons[current].GraphQL,
215-
lagoonCLIConfig.Lagoons[current].Token,
216+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
216217
lagoonCLIConfig.Lagoons[current].Version,
217218
lagoonCLIVersion,
218219
debug,
@@ -297,7 +298,7 @@ var deleteDeployTargetCmd = &cobra.Command{
297298
current := lagoonCLIConfig.Current
298299
lc := client.New(
299300
lagoonCLIConfig.Lagoons[current].GraphQL,
300-
lagoonCLIConfig.Lagoons[current].Token,
301+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
301302
lagoonCLIConfig.Lagoons[current].Version,
302303
lagoonCLIVersion,
303304
debug,
@@ -349,7 +350,7 @@ var addDeployTargetToOrganizationCmd = &cobra.Command{
349350
}
350351

351352
current := lagoonCLIConfig.Current
352-
token := lagoonCLIConfig.Lagoons[current].Token
353+
token := lagoonCLIConfig.Lagoons[current].Grant.AccessToken
353354
lc := lclient.New(
354355
lagoonCLIConfig.Lagoons[current].GraphQL,
355356
lagoonCLIVersion,
@@ -406,7 +407,7 @@ var RemoveDeployTargetFromOrganizationCmd = &cobra.Command{
406407
}
407408

408409
current := lagoonCLIConfig.Current
409-
token := lagoonCLIConfig.Lagoons[current].Token
410+
token := lagoonCLIConfig.Lagoons[current].Grant.AccessToken
410411
lc := lclient.New(
411412
lagoonCLIConfig.Lagoons[current].GraphQL,
412413
lagoonCLIVersion,

cmd/deploytargetconfig.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"context"
55
"fmt"
6+
67
l "github.com/uselagoon/machinery/api/lagoon"
78
lclient "github.com/uselagoon/machinery/api/lagoon/client"
89
s "github.com/uselagoon/machinery/api/schema"
@@ -57,7 +58,7 @@ var addDeployTargetConfigCmd = &cobra.Command{
5758
return fmt.Errorf("Missing arguments: branches is a required flag")
5859
}
5960
current := lagoonCLIConfig.Current
60-
token := lagoonCLIConfig.Lagoons[current].Token
61+
token := lagoonCLIConfig.Lagoons[current].Grant.AccessToken
6162
lc := lclient.New(
6263
lagoonCLIConfig.Lagoons[current].GraphQL,
6364
lagoonCLIVersion,
@@ -153,7 +154,7 @@ var updateDeployTargetConfigCmd = &cobra.Command{
153154
current := lagoonCLIConfig.Current
154155
lc := client.New(
155156
lagoonCLIConfig.Lagoons[current].GraphQL,
156-
lagoonCLIConfig.Lagoons[current].Token,
157+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
157158
lagoonCLIConfig.Lagoons[current].Version,
158159
lagoonCLIVersion,
159160
debug)
@@ -229,7 +230,7 @@ var deleteDeployTargetConfigCmd = &cobra.Command{
229230
current := lagoonCLIConfig.Current
230231
lc := client.New(
231232
lagoonCLIConfig.Lagoons[current].GraphQL,
232-
lagoonCLIConfig.Lagoons[current].Token,
233+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
233234
lagoonCLIConfig.Lagoons[current].Version,
234235
lagoonCLIVersion,
235236
debug)
@@ -265,7 +266,7 @@ var listDeployTargetConfigsCmd = &cobra.Command{
265266
current := lagoonCLIConfig.Current
266267
lc := client.New(
267268
lagoonCLIConfig.Lagoons[current].GraphQL,
268-
lagoonCLIConfig.Lagoons[current].Token,
269+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
269270
lagoonCLIConfig.Lagoons[current].Version,
270271
lagoonCLIVersion,
271272
debug)

cmd/environment.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ package cmd
33
import (
44
"context"
55
"fmt"
6-
s "github.com/uselagoon/machinery/api/schema"
76
"os"
87
"strings"
98

9+
s "github.com/uselagoon/machinery/api/schema"
10+
1011
"github.com/spf13/cobra"
1112
"github.com/spf13/pflag"
1213
"github.com/uselagoon/lagoon-cli/internal/lagoon"
@@ -100,7 +101,7 @@ var updateEnvironmentCmd = &cobra.Command{
100101
}
101102

102103
current := lagoonCLIConfig.Current
103-
token := lagoonCLIConfig.Lagoons[current].Token
104+
token := lagoonCLIConfig.Lagoons[current].Grant.AccessToken
104105
lc := lclient.New(
105106
lagoonCLIConfig.Lagoons[current].GraphQL,
106107
lagoonCLIVersion,
@@ -182,7 +183,7 @@ var listBackupsCmd = &cobra.Command{
182183
current := lagoonCLIConfig.Current
183184
lc := client.New(
184185
lagoonCLIConfig.Lagoons[current].GraphQL,
185-
lagoonCLIConfig.Lagoons[current].Token,
186+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
186187
lagoonCLIConfig.Lagoons[current].Version,
187188
lagoonCLIVersion,
188189
debug)
@@ -249,7 +250,7 @@ This returns a direct URL to the backup, this is a signed download link with a l
249250
current := lagoonCLIConfig.Current
250251
lc := client.New(
251252
lagoonCLIConfig.Lagoons[current].GraphQL,
252-
lagoonCLIConfig.Lagoons[current].Token,
253+
lagoonCLIConfig.Lagoons[current].Grant.AccessToken,
253254
lagoonCLIConfig.Lagoons[current].Version,
254255
lagoonCLIVersion,
255256
debug)

0 commit comments

Comments
 (0)