Skip to content

Commit

Permalink
feat: add support for aws managed grafana (#96)
Browse files Browse the repository at this point in the history
This adds a new login method for AWS Managed Grafana Instances. If the
user account has MFA enabled, it waits for the user to input the OTP
and then continues with the normal flow of waiting for a non existing
element to be visible to exit.
  • Loading branch information
pkarakal authored Mar 25, 2023
1 parent d91823c commit e3cc913
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 4 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The utitilty provides these options:
- to a Grafana server with anonymous-mode enabled (same method used on [play.grafana.org](https://play.grafana.org))
- to a Grafana Cloud instance
- to a Grafana server with OAuth enabled
- to an AWS Managed Grafana instance (both with and without MFA)
- Switch to kiosk or kiosk-tv mode
- Display the default home page set for the user
- Display a specified dashboard
Expand Down Expand Up @@ -80,7 +81,7 @@ NOTE: Flags with parameters should use an "equals" (-autofit=true, -URL=https://
disabled = omit option
(default "full")
-login-method string
[anon|local|gcom|goauth|idtoken|apikey] (default "anon")
[anon|local|gcom|goauth|idtoken|apikey|aws] (default "anon")
-lxde
Initialize LXDE for kiosk mode
-lxde-home string
Expand All @@ -91,6 +92,8 @@ NOTE: Flags with parameters should use an "equals" (-autofit=true, -URL=https://
URL is a playlist
-username string
username (default "guest")
-use-mfa
MFA is enabled for given account (default false)
-window-position string
Top Left Position of Kiosk (default "0,0")
-window-size string
Expand Down Expand Up @@ -143,7 +146,7 @@ They can also be used instead of a configuration file.
KIOSK_IS_PLAYLIST bool
URL is a playlist (default "false")
KIOSK_LOGIN_METHOD string
[anon|local|gcom|goauth|idtoken|apikey] (default "anon")
[anon|local|gcom|goauth|idtoken|apikey|aws] (default "anon")
KIOSK_LOGIN_PASSWORD string
password (default "guest")
KIOSK_URL string
Expand Down
1 change: 1 addition & 0 deletions config-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ target:
username: user
password: changeme
playlist: false
use-mfa: false
URL: https://play.grafana.org
ignore-certificate-errors: false

Expand Down
11 changes: 9 additions & 2 deletions pkg/cmd/grafana-kiosk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Args struct {
IsPlayList bool
OauthAutoLogin bool
LXDEEnabled bool
UseMFA bool
Audience string
KeyFile string
Apikey string
Expand All @@ -42,9 +43,10 @@ func ProcessArgs(cfg interface{}) Args {

flagSettings := flag.NewFlagSet("grafana-kiosk", flag.ContinueOnError)
flagSettings.StringVar(&processedArgs.ConfigPath, "c", "", "Path to configuration file (config.yaml)")
flagSettings.StringVar(&processedArgs.LoginMethod, "login-method", "anon", "[anon|local|gcom|goauth|idtoken|apikey]")
flagSettings.StringVar(&processedArgs.LoginMethod, "login-method", "anon", "[anon|local|gcom|goauth|idtoken|apikey|aws]")
flagSettings.StringVar(&processedArgs.Username, "username", "guest", "username")
flagSettings.StringVar(&processedArgs.Password, "password", "guest", "password")
flagSettings.BoolVar(&processedArgs.UseMFA, "use-mfa", false, "password")
flagSettings.StringVar(&processedArgs.Mode, "kiosk-mode", "full", "Kiosk Display Mode [full|tv|disabled]\nfull = No TOPNAV and No SIDEBAR\ntv = No SIDEBAR\ndisabled = omit option\n")
flagSettings.StringVar(&processedArgs.URL, "URL", "https://play.grafana.org", "URL to Grafana server")
flagSettings.StringVar(&processedArgs.WindowPosition, "window-position", "0,0", "Top Left Position of Kiosk")
Expand Down Expand Up @@ -122,6 +124,7 @@ func summary(cfg *kiosk.Config) {
log.Println("Password:", "*redacted*")
log.Println("IgnoreCertificateErrors:", cfg.Target.IgnoreCertificateErrors)
log.Println("IsPlayList:", cfg.Target.IsPlayList)
log.Println("UseMFA:", cfg.Target.UseMFA)
// goauth
log.Println("Fieldname AutoLogin:", cfg.GOAUTH.AutoLogin)
log.Println("Fieldname Username:", cfg.GOAUTH.UsernameField)
Expand All @@ -135,7 +138,7 @@ func main() {

// validate auth methods
switch args.LoginMethod {
case "goauth", "anon", "local", "gcom", "idtoken", "apikey":
case "goauth", "anon", "local", "gcom", "idtoken", "apikey", "aws":
default:
log.Println("Invalid auth method", args.LoginMethod)
os.Exit(-1)
Expand All @@ -162,6 +165,7 @@ func main() {
cfg.Target.Password = args.Password
cfg.Target.IgnoreCertificateErrors = args.IgnoreCertificateErrors
cfg.Target.IsPlayList = args.IsPlayList
cfg.Target.UseMFA = args.UseMFA
//
cfg.General.AutoFit = args.AutoFit
cfg.General.LXDEEnabled = args.LXDEEnabled
Expand Down Expand Up @@ -217,6 +221,9 @@ func main() {
case "apikey":
log.Printf("Launching apikey kiosk")
kiosk.GrafanaKioskApikey(&cfg)
case "aws":
log.Printf("Launcing AWS SSO kiosk")
kiosk.GrafanaKioskAWSLogin(&cfg)
default:
log.Printf("Launching ANON login kiosk")
kiosk.GrafanaKioskAnonymous(&cfg)
Expand Down
69 changes: 69 additions & 0 deletions pkg/kiosk/aws_login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package kiosk

import (
"context"
"github.com/chromedp/chromedp"
"github.com/chromedp/chromedp/kb"
"log"
"os"
"time"
)

func GrafanaKioskAWSLogin(cfg *Config) {
dir, err := os.MkdirTemp(os.TempDir(), "chromedp-kiosk")
if err != nil {
panic(err)
}

log.Println("Using temp dir:", dir)
defer os.RemoveAll(dir)

opts := generateExecutorOptions(dir, cfg.General.WindowPosition, cfg.Target.IgnoreCertificateErrors)

allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()

// also set up a custom logger
taskCtx, cancel := chromedp.NewContext(allocCtx, chromedp.WithLogf(log.Printf))
defer cancel()

listenChromeEvents(taskCtx, targetCrashed)

// ensure that the browser process is started
if err := chromedp.Run(taskCtx); err != nil {
panic(err)
}

var generatedURL = GenerateURL(cfg.Target.URL, cfg.General.Mode, cfg.General.AutoFit, cfg.Target.IsPlayList)

log.Println("Navigating to ", generatedURL)

// Give browser time to load next page (this can be prone to failure, explore different options vs sleeping)
time.Sleep(2000 * time.Millisecond)

if err := chromedp.Run(taskCtx,
chromedp.Navigate(generatedURL),
chromedp.WaitVisible(`//a[contains(@href,'login/sso')]`, chromedp.BySearch),
chromedp.Click(`//a[contains(@href,'login/sso')]`, chromedp.BySearch),
chromedp.WaitVisible(`input#awsui-input-0`, chromedp.BySearch),
chromedp.SendKeys(`input#awsui-input-0`, cfg.Target.Username+kb.Enter, chromedp.BySearch),
chromedp.WaitVisible(`input#awsui-input-1`, chromedp.BySearch),
chromedp.SendKeys(`input#awsui-input-1`, cfg.Target.Password+kb.Enter, chromedp.BySearch),
); err != nil {
panic(err)
}

if cfg.Target.UseMFA {
if err := chromedp.Run(taskCtx,
chromedp.WaitNotVisible(`input#awsui-input-2`, chromedp.BySearch),
); err != nil {
panic(err)
}
}

if err := chromedp.Run(taskCtx,
chromedp.WaitVisible(`notinputPassword`, chromedp.ByID),
); err != nil {
panic(err)
}
}
1 change: 1 addition & 0 deletions pkg/kiosk/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Config struct {
Target struct {
IgnoreCertificateErrors bool `yaml:"ignore-certificate-errors" env:"KIOSK_IGNORE_CERTIFICATE_ERRORS" env-description:"ignore SSL/TLS certificate errors" env-default:"false"`
IsPlayList bool `yaml:"playlist" env:"KIOSK_IS_PLAYLIST" env-default:"false" env-description:"URL is a playlist"`
UseMFA bool `yaml:"use-mfa" env:"KIOSK_USE_MFA" env-default:"false" env-description:"MFA is enabled for given account"`
LoginMethod string `yaml:"login-method" env:"KIOSK_LOGIN_METHOD" env-default:"anon" env-description:"[anon|local|gcom|goauth|idtoken]"`
Password string `yaml:"password" env:"KIOSK_LOGIN_PASSWORD" env-default:"guest" env-description:"password"`
URL string `yaml:"URL" env:"KIOSK_URL" env-default:"https://play.grafana.org" env-description:"URL to Grafana server"`
Expand Down

0 comments on commit e3cc913

Please sign in to comment.