Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for Grafana API key Auth #93

Merged
merged 1 commit into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ NOTE: Flags with parameters should use an "equals" (-autofit=true, -URL=https://
```TEXT
-URL string
URL to Grafana server (default "https://play.grafana.org")
-apikey string
apikey
-audience string
idtoken audience
-auto-login
Expand All @@ -78,7 +80,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] (default "anon")
[anon|local|gcom|goauth|idtoken|apikey] (default "anon")
-lxde
Initialize LXDE for kiosk mode
-lxde-home string
Expand Down Expand Up @@ -137,7 +139,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] (default "anon")
[anon|local|gcom|goauth|idtoken|apikey] (default "anon")
KIOSK_LOGIN_PASSWORD string
password (default "guest")
KIOSK_URL string
Expand All @@ -154,6 +156,8 @@ They can also be used instead of a configuration file.
JSON Credentials for idtoken
KIOSK_IDTOKEN_AUDIENCE string
Audience for idtoken, tpyically your oauth client id
KIOSK_APIKEY_APIKEY string
Grafana API keys
```

### Hosted Grafana using grafana.com authentication
Expand Down Expand Up @@ -204,6 +208,13 @@ This will take the browser to a playlist on play.grafana.org in fullscreen kiosk
./bin/grafana-kiosk -URL=https://play.grafana.org/playlists/play/1 -login-method=anon -kiosk-mode=tv
```

### Grafana Server with Api Key

This will take the browser to the default dashboard on play.grafana.org in fullscreen kiosk mode:
```bash
./bin/grafana-kiosk -URL=https://play.grafana.org -login-method apikey --apikey "xxxxxxxxxxxxxxx" -kiosk-mode=tv
```

### Grafana Server with Generic Oauth

This will login to a Generic Oauth service, configured on Grafana. Oauth_auto_login is disabeld. As Oauth provider is Keycloak used.
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 @@ -22,6 +22,7 @@ type Args struct {
LXDEEnabled bool
Audience string
KeyFile string
Apikey string
LXDEHome string
ConfigPath string
Mode string
Expand All @@ -40,7 +41,7 @@ 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]")
flagSettings.StringVar(&processedArgs.LoginMethod, "login-method", "anon", "[anon|local|gcom|goauth|idtoken|apikey]")
flagSettings.StringVar(&processedArgs.Username, "username", "guest", "username")
flagSettings.StringVar(&processedArgs.Password, "password", "guest", "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")
Expand All @@ -56,6 +57,7 @@ func ProcessArgs(cfg interface{}) Args {
flagSettings.StringVar(&processedArgs.PasswordField, "field-password", "password", "Fieldname for the password")
flagSettings.StringVar(&processedArgs.Audience, "audience", "", "idtoken audience")
flagSettings.StringVar(&processedArgs.KeyFile, "keyfile", "key.json", "idtoken json credentials")
flagSettings.StringVar(&processedArgs.Apikey, "apikey", "", "apikey")

fu := flagSettings.Usage
flagSettings.Usage = func() {
Expand Down Expand Up @@ -126,7 +128,7 @@ func main() {

// validate auth methods
switch args.LoginMethod {
case "goauth", "anon", "local", "gcom", "idtoken":
case "goauth", "anon", "local", "gcom", "idtoken", "apikey":
default:
log.Println("Invalid auth method", args.LoginMethod)
os.Exit(-1)
Expand Down Expand Up @@ -166,6 +168,8 @@ func main() {

cfg.IDTOKEN.Audience = args.Audience
cfg.IDTOKEN.KeyFile = args.KeyFile

cfg.APIKEY.Apikey = args.Apikey
}

summary(&cfg)
Expand Down Expand Up @@ -202,6 +206,9 @@ func main() {
case "idtoken":
log.Printf("Launching idtoken oauth kiosk")
kiosk.GrafanaKioskIDToken(&cfg)
case "apikey":
log.Printf("Launching apikey kiosk")
kiosk.GrafanaKioskApikey(&cfg)
default:
log.Printf("Launching ANON login kiosk")
kiosk.GrafanaKioskAnonymous(&cfg)
Expand Down
67 changes: 67 additions & 0 deletions pkg/kiosk/apikey_login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package kiosk

import (
"context"
"log"
"os"
"time"


"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
)

// GrafanaKioskApikey creates a chrome-based kiosk using a grafana api key.
func GrafanaKioskApikey(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, consoleAPICall|targetCrashed)

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

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

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

log.Println("Navigating to ", generatedURL)
/*
Launch chrome and look for main-view element
*/
headers := map[string]interface{}{
"Authorization": "Bearer " + cfg.APIKEY.Apikey,
}
if err := chromedp.Run(taskCtx,
network.Enable(),
network.SetExtraHTTPHeaders(network.Headers(headers)),
chromedp.Navigate(generatedURL),
chromedp.WaitVisible(`//div[@class="main-view"]`, chromedp.BySearch),
// wait forever (for now)
chromedp.WaitVisible("notinputPassword", chromedp.ByID),
); err != nil {
panic(err)
}

log.Println("Sleep before exit...")
// wait here for the process to exit
time.Sleep(2000 * time.Millisecond)
log.Println("Exit...")
}
3 changes: 3 additions & 0 deletions pkg/kiosk/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ type Config struct {
KeyFile string `yaml:"idtoken-keyfile" env:"KIOSK_IDTOKEN_KEYFILE" env-default:"key.json" env-description:"JSON Credentials for idtoken"`
Audience string `yaml:"idtoken-audience" env:"KIOSK_IDTOKEN_AUDIENCE" env-description:"Audience for idtoken, tpyically your oauth client id"`
} `yaml:"idtoken"`
APIKEY struct {
Apikey string `yaml:"apikey" env:"KIOSK_APIKEY_APIKEY" env-description:"APIKEY"`
} `yaml:"apikey"`
}