2019-10-30 03:54:47 +07:00
package main
import (
"fmt"
"os"
"os/exec"
"strings"
2020-11-25 05:54:36 +07:00
log "github.com/sirupsen/logrus"
2019-10-30 03:54:47 +07:00
"github.com/spf13/cobra"
2020-04-05 19:37:21 +07:00
2021-08-11 08:04:35 +07:00
"github.com/authelia/authelia/v4/internal/utils"
2019-10-30 03:54:47 +07:00
)
2020-05-02 12:06:39 +07:00
// HostEntry represents an entry in /etc/hosts.
2019-10-30 03:54:47 +07:00
type HostEntry struct {
Domain string
IP string
}
var hostEntries = [ ] HostEntry {
2022-04-05 06:57:47 +07:00
// For unit tests.
{ Domain : "local.example.com" , IP : "127.0.0.1" } ,
2020-05-02 12:06:39 +07:00
// For authelia backend.
2020-04-09 08:05:17 +07:00
{ Domain : "authelia.example.com" , IP : "192.168.240.50" } ,
feat(session): add redis sentinel provider (#1768)
* feat(session): add redis sentinel provider
* refactor(session): use int for ports as per go standards
* refactor(configuration): adjust tests and validation
* refactor(configuration): add err format consts
* refactor(configuration): explicitly map redis structs
* refactor(session): merge redis/redis sentinel providers
* refactor(session): add additional checks to redis providers
* feat(session): add redis cluster provider
* fix: update config for new values
* fix: provide nil certpool to affected tests/mocks
* test: add additional tests to cover uncovered code
* docs: expand explanation of host and nodes relation for redis
* ci: add redis-sentinel to suite highavailability, add redis-sentinel quorum
* fix(session): sentinel password
* test: use redis alpine library image for redis sentinel, use expose instead of ports, use redis ip, adjust redis ip range, adjust redis config
* test: make entrypoint.sh executable, fix entrypoint.sh if/elif
* test: add redis failover tests
* test: defer docker start, adjust sleep, attempt logout before login, attempt visit before login and tune timeouts, add additional logging
* test: add sentinel integration test
* test: add secondary node failure to tests, fix password usage, bump test timeout, add sleep
* feat: use sentinel failover cluster
* fix: renamed addrs to sentineladdrs upstream
* test(session): sentinel failover
* test: add redis standard back into testing
* test: move redis standalone test to traefik2
* fix/docs: apply suggestions from code review
2021-03-10 06:03:05 +07:00
2020-05-02 12:06:39 +07:00
// For common tests.
2020-04-09 08:05:17 +07:00
{ Domain : "login.example.com" , IP : "192.168.240.100" } ,
{ Domain : "admin.example.com" , IP : "192.168.240.100" } ,
{ Domain : "singlefactor.example.com" , IP : "192.168.240.100" } ,
{ Domain : "dev.example.com" , IP : "192.168.240.100" } ,
{ Domain : "home.example.com" , IP : "192.168.240.100" } ,
{ Domain : "mx1.mail.example.com" , IP : "192.168.240.100" } ,
{ Domain : "mx2.mail.example.com" , IP : "192.168.240.100" } ,
{ Domain : "public.example.com" , IP : "192.168.240.100" } ,
{ Domain : "secure.example.com" , IP : "192.168.240.100" } ,
{ Domain : "mail.example.com" , IP : "192.168.240.100" } ,
{ Domain : "duo.example.com" , IP : "192.168.240.100" } ,
feat(session): add redis sentinel provider (#1768)
* feat(session): add redis sentinel provider
* refactor(session): use int for ports as per go standards
* refactor(configuration): adjust tests and validation
* refactor(configuration): add err format consts
* refactor(configuration): explicitly map redis structs
* refactor(session): merge redis/redis sentinel providers
* refactor(session): add additional checks to redis providers
* feat(session): add redis cluster provider
* fix: update config for new values
* fix: provide nil certpool to affected tests/mocks
* test: add additional tests to cover uncovered code
* docs: expand explanation of host and nodes relation for redis
* ci: add redis-sentinel to suite highavailability, add redis-sentinel quorum
* fix(session): sentinel password
* test: use redis alpine library image for redis sentinel, use expose instead of ports, use redis ip, adjust redis ip range, adjust redis config
* test: make entrypoint.sh executable, fix entrypoint.sh if/elif
* test: add redis failover tests
* test: defer docker start, adjust sleep, attempt logout before login, attempt visit before login and tune timeouts, add additional logging
* test: add sentinel integration test
* test: add secondary node failure to tests, fix password usage, bump test timeout, add sleep
* feat: use sentinel failover cluster
* fix: renamed addrs to sentineladdrs upstream
* test(session): sentinel failover
* test: add redis standard back into testing
* test: move redis standalone test to traefik2
* fix/docs: apply suggestions from code review
2021-03-10 06:03:05 +07:00
2020-05-02 12:06:39 +07:00
// For Traefik suite.
2020-04-09 08:05:17 +07:00
{ Domain : "traefik.example.com" , IP : "192.168.240.100" } ,
feat(session): add redis sentinel provider (#1768)
* feat(session): add redis sentinel provider
* refactor(session): use int for ports as per go standards
* refactor(configuration): adjust tests and validation
* refactor(configuration): add err format consts
* refactor(configuration): explicitly map redis structs
* refactor(session): merge redis/redis sentinel providers
* refactor(session): add additional checks to redis providers
* feat(session): add redis cluster provider
* fix: update config for new values
* fix: provide nil certpool to affected tests/mocks
* test: add additional tests to cover uncovered code
* docs: expand explanation of host and nodes relation for redis
* ci: add redis-sentinel to suite highavailability, add redis-sentinel quorum
* fix(session): sentinel password
* test: use redis alpine library image for redis sentinel, use expose instead of ports, use redis ip, adjust redis ip range, adjust redis config
* test: make entrypoint.sh executable, fix entrypoint.sh if/elif
* test: add redis failover tests
* test: defer docker start, adjust sleep, attempt logout before login, attempt visit before login and tune timeouts, add additional logging
* test: add sentinel integration test
* test: add secondary node failure to tests, fix password usage, bump test timeout, add sleep
* feat: use sentinel failover cluster
* fix: renamed addrs to sentineladdrs upstream
* test(session): sentinel failover
* test: add redis standard back into testing
* test: move redis standalone test to traefik2
* fix/docs: apply suggestions from code review
2021-03-10 06:03:05 +07:00
2020-05-02 12:06:39 +07:00
// For HAProxy suite.
2020-04-09 08:05:17 +07:00
{ Domain : "haproxy.example.com" , IP : "192.168.240.100" } ,
feat(session): add redis sentinel provider (#1768)
* feat(session): add redis sentinel provider
* refactor(session): use int for ports as per go standards
* refactor(configuration): adjust tests and validation
* refactor(configuration): add err format consts
* refactor(configuration): explicitly map redis structs
* refactor(session): merge redis/redis sentinel providers
* refactor(session): add additional checks to redis providers
* feat(session): add redis cluster provider
* fix: update config for new values
* fix: provide nil certpool to affected tests/mocks
* test: add additional tests to cover uncovered code
* docs: expand explanation of host and nodes relation for redis
* ci: add redis-sentinel to suite highavailability, add redis-sentinel quorum
* fix(session): sentinel password
* test: use redis alpine library image for redis sentinel, use expose instead of ports, use redis ip, adjust redis ip range, adjust redis config
* test: make entrypoint.sh executable, fix entrypoint.sh if/elif
* test: add redis failover tests
* test: defer docker start, adjust sleep, attempt logout before login, attempt visit before login and tune timeouts, add additional logging
* test: add sentinel integration test
* test: add secondary node failure to tests, fix password usage, bump test timeout, add sleep
* feat: use sentinel failover cluster
* fix: renamed addrs to sentineladdrs upstream
* test(session): sentinel failover
* test: add redis standard back into testing
* test: move redis standalone test to traefik2
* fix/docs: apply suggestions from code review
2021-03-10 06:03:05 +07:00
2020-05-02 12:06:39 +07:00
// For testing network ACLs.
2020-04-09 08:05:17 +07:00
{ Domain : "proxy-client1.example.com" , IP : "192.168.240.201" } ,
{ Domain : "proxy-client2.example.com" , IP : "192.168.240.202" } ,
{ Domain : "proxy-client3.example.com" , IP : "192.168.240.203" } ,
feat(session): add redis sentinel provider (#1768)
* feat(session): add redis sentinel provider
* refactor(session): use int for ports as per go standards
* refactor(configuration): adjust tests and validation
* refactor(configuration): add err format consts
* refactor(configuration): explicitly map redis structs
* refactor(session): merge redis/redis sentinel providers
* refactor(session): add additional checks to redis providers
* feat(session): add redis cluster provider
* fix: update config for new values
* fix: provide nil certpool to affected tests/mocks
* test: add additional tests to cover uncovered code
* docs: expand explanation of host and nodes relation for redis
* ci: add redis-sentinel to suite highavailability, add redis-sentinel quorum
* fix(session): sentinel password
* test: use redis alpine library image for redis sentinel, use expose instead of ports, use redis ip, adjust redis ip range, adjust redis config
* test: make entrypoint.sh executable, fix entrypoint.sh if/elif
* test: add redis failover tests
* test: defer docker start, adjust sleep, attempt logout before login, attempt visit before login and tune timeouts, add additional logging
* test: add sentinel integration test
* test: add secondary node failure to tests, fix password usage, bump test timeout, add sleep
* feat: use sentinel failover cluster
* fix: renamed addrs to sentineladdrs upstream
* test(session): sentinel failover
* test: add redis standard back into testing
* test: move redis standalone test to traefik2
* fix/docs: apply suggestions from code review
2021-03-10 06:03:05 +07:00
2022-01-31 12:25:15 +07:00
// Redis Replicas.
feat(session): add redis sentinel provider (#1768)
* feat(session): add redis sentinel provider
* refactor(session): use int for ports as per go standards
* refactor(configuration): adjust tests and validation
* refactor(configuration): add err format consts
* refactor(configuration): explicitly map redis structs
* refactor(session): merge redis/redis sentinel providers
* refactor(session): add additional checks to redis providers
* feat(session): add redis cluster provider
* fix: update config for new values
* fix: provide nil certpool to affected tests/mocks
* test: add additional tests to cover uncovered code
* docs: expand explanation of host and nodes relation for redis
* ci: add redis-sentinel to suite highavailability, add redis-sentinel quorum
* fix(session): sentinel password
* test: use redis alpine library image for redis sentinel, use expose instead of ports, use redis ip, adjust redis ip range, adjust redis config
* test: make entrypoint.sh executable, fix entrypoint.sh if/elif
* test: add redis failover tests
* test: defer docker start, adjust sleep, attempt logout before login, attempt visit before login and tune timeouts, add additional logging
* test: add sentinel integration test
* test: add secondary node failure to tests, fix password usage, bump test timeout, add sleep
* feat: use sentinel failover cluster
* fix: renamed addrs to sentineladdrs upstream
* test(session): sentinel failover
* test: add redis standard back into testing
* test: move redis standalone test to traefik2
* fix/docs: apply suggestions from code review
2021-03-10 06:03:05 +07:00
{ Domain : "redis-node-0.example.com" , IP : "192.168.240.110" } ,
{ Domain : "redis-node-1.example.com" , IP : "192.168.240.111" } ,
{ Domain : "redis-node-2.example.com" , IP : "192.168.240.112" } ,
2022-01-31 12:25:15 +07:00
// Redis Sentinel Replicas.
feat(session): add redis sentinel provider (#1768)
* feat(session): add redis sentinel provider
* refactor(session): use int for ports as per go standards
* refactor(configuration): adjust tests and validation
* refactor(configuration): add err format consts
* refactor(configuration): explicitly map redis structs
* refactor(session): merge redis/redis sentinel providers
* refactor(session): add additional checks to redis providers
* feat(session): add redis cluster provider
* fix: update config for new values
* fix: provide nil certpool to affected tests/mocks
* test: add additional tests to cover uncovered code
* docs: expand explanation of host and nodes relation for redis
* ci: add redis-sentinel to suite highavailability, add redis-sentinel quorum
* fix(session): sentinel password
* test: use redis alpine library image for redis sentinel, use expose instead of ports, use redis ip, adjust redis ip range, adjust redis config
* test: make entrypoint.sh executable, fix entrypoint.sh if/elif
* test: add redis failover tests
* test: defer docker start, adjust sleep, attempt logout before login, attempt visit before login and tune timeouts, add additional logging
* test: add sentinel integration test
* test: add secondary node failure to tests, fix password usage, bump test timeout, add sleep
* feat: use sentinel failover cluster
* fix: renamed addrs to sentineladdrs upstream
* test(session): sentinel failover
* test: add redis standard back into testing
* test: move redis standalone test to traefik2
* fix/docs: apply suggestions from code review
2021-03-10 06:03:05 +07:00
{ Domain : "redis-sentinel-0.example.com" , IP : "192.168.240.120" } ,
{ Domain : "redis-sentinel-1.example.com" , IP : "192.168.240.121" } ,
{ Domain : "redis-sentinel-2.example.com" , IP : "192.168.240.122" } ,
2020-05-02 12:06:39 +07:00
// Kubernetes dashboard.
2020-04-09 08:05:17 +07:00
{ Domain : "kubernetes.example.com" , IP : "192.168.240.110" } ,
2022-01-31 12:25:15 +07:00
// OIDC tester app.
2021-05-05 05:06:05 +07:00
{ Domain : "oidc.example.com" , IP : "192.168.240.100" } ,
{ Domain : "oidc-public.example.com" , IP : "192.168.240.100" } ,
2019-10-30 03:54:47 +07:00
}
func runCommand ( cmd string , args ... string ) {
2019-11-02 21:32:58 +07:00
command := utils . CommandWithStdout ( cmd , args ... )
2019-10-30 03:54:47 +07:00
err := command . Run ( )
if err != nil {
panic ( err )
}
}
2021-10-10 01:41:02 +07:00
func checkCommandExist ( cmd string , resolutionHint string ) {
2019-10-30 03:54:47 +07:00
fmt . Print ( "Checking if '" + cmd + "' command is installed..." )
2020-05-05 14:57:30 +07:00
command := exec . Command ( "bash" , "-c" , "command -v " + cmd ) //nolint:gosec // Used only in development.
2019-10-30 03:54:47 +07:00
err := command . Run ( )
if err != nil {
2021-10-10 01:41:02 +07:00
msg := "[ERROR] You must install " + cmd + " on your machine."
if resolutionHint != "" {
msg += fmt . Sprintf ( " %s" , resolutionHint )
}
log . Fatal ( msg )
2019-10-30 03:54:47 +07:00
}
fmt . Println ( " OK" )
}
func createTemporaryDirectory ( ) {
err := os . MkdirAll ( "/tmp/authelia" , 0755 )
if err != nil {
panic ( err )
}
}
func bootstrapPrintln ( args ... interface { } ) {
a := make ( [ ] interface { } , 0 )
a = append ( a , "[BOOTSTRAP]" )
a = append ( a , args ... )
fmt . Println ( a ... )
}
func shell ( cmd string ) {
runCommand ( "bash" , "-c" , cmd )
}
func prepareHostsFile ( ) {
contentBytes , err := readHostsFile ( )
if err != nil {
panic ( err )
}
lines := strings . Split ( string ( contentBytes ) , "\n" )
toBeAddedLine := make ( [ ] string , 0 )
modified := false
for _ , entry := range hostEntries {
domainInHostFile := false
2020-05-06 02:35:32 +07:00
2019-10-30 03:54:47 +07:00
for i , line := range lines {
domainFound := strings . Contains ( line , entry . Domain )
ipFound := strings . Contains ( line , entry . IP )
if domainFound {
domainInHostFile = true
// The IP is not up to date.
if ipFound {
break
} else {
lines [ i ] = entry . IP + " " + entry . Domain
modified = true
break
}
}
}
if ! domainInHostFile {
toBeAddedLine = append ( toBeAddedLine , entry . IP + " " + entry . Domain )
}
}
if len ( toBeAddedLine ) > 0 {
lines = append ( lines , toBeAddedLine ... )
modified = true
}
2021-12-01 20:14:15 +07:00
fd , err := os . CreateTemp ( "/tmp/authelia/" , "hosts" )
2020-05-05 14:57:30 +07:00
if err != nil {
panic ( err )
}
2019-10-30 03:54:47 +07:00
2020-05-05 14:57:30 +07:00
_ , err = fd . Write ( [ ] byte ( strings . Join ( lines , "\n" ) ) )
2019-10-30 03:54:47 +07:00
if err != nil {
panic ( err )
}
if modified {
bootstrapPrintln ( "/etc/hosts needs to be updated" )
2020-05-05 14:57:30 +07:00
shell ( fmt . Sprintf ( "cat %s | sudo tee /etc/hosts > /dev/null" , fd . Name ( ) ) )
}
err = fd . Close ( )
if err != nil {
panic ( err )
2019-10-30 03:54:47 +07:00
}
}
// ReadHostsFile reads the hosts file.
func readHostsFile ( ) ( [ ] byte , error ) {
2021-12-01 20:14:15 +07:00
bs , err := os . ReadFile ( "/etc/hosts" )
2019-10-30 03:54:47 +07:00
if err != nil {
return nil , err
}
2020-05-06 02:35:32 +07:00
2019-10-30 03:54:47 +07:00
return bs , nil
}
func readVersion ( cmd string , args ... string ) {
command := exec . Command ( cmd , args ... )
b , err := command . Output ( )
if err != nil {
panic ( err )
}
fmt . Print ( cmd + " => " + string ( b ) )
}
func readVersions ( ) {
readVersion ( "go" , "version" )
readVersion ( "node" , "--version" )
2021-09-29 14:24:21 +07:00
readVersion ( "pnpm" , "--version" )
2019-10-30 03:54:47 +07:00
readVersion ( "docker" , "--version" )
2021-09-29 14:24:21 +07:00
readVersion ( "docker-compose" , "version" )
2019-10-30 03:54:47 +07:00
}
2020-05-02 12:06:39 +07:00
// Bootstrap bootstrap authelia dev environment.
2019-10-30 03:54:47 +07:00
func Bootstrap ( cobraCmd * cobra . Command , args [ ] string ) {
bootstrapPrintln ( "Checking command installation..." )
2021-10-10 01:41:02 +07:00
checkCommandExist ( "node" , "Follow installation guidelines from https://nodejs.org/en/download/package-manager/ or download installer from https://nodejs.org/en/download/" )
checkCommandExist ( "pnpm" , "Follow installation guidelines from https://pnpm.io/installation" )
checkCommandExist ( "docker" , "Follow installation guidelines from https://docs.docker.com/get-docker/" )
checkCommandExist ( "docker-compose" , "Follow installation guidelines from https://docs.docker.com/compose/install/" )
2019-10-30 03:54:47 +07:00
bootstrapPrintln ( "Getting versions of tools" )
readVersions ( )
2019-11-02 21:32:58 +07:00
bootstrapPrintln ( "Checking if GOPATH is set" )
goPathFound := false
2020-05-06 02:35:32 +07:00
2019-11-02 21:32:58 +07:00
for _ , v := range os . Environ ( ) {
if strings . HasPrefix ( v , "GOPATH=" ) {
goPathFound = true
break
}
}
if ! goPathFound {
log . Fatal ( "GOPATH is not set" )
}
2019-10-30 03:54:47 +07:00
createTemporaryDirectory ( )
bootstrapPrintln ( "Preparing /etc/hosts to serve subdomains of example.com..." )
prepareHostsFile ( )
2019-11-17 22:31:27 +07:00
fmt . Println ( )
2019-11-02 21:32:58 +07:00
bootstrapPrintln ( "Run 'authelia-scripts suites setup Standalone' to start Authelia and visit https://home.example.com:8080." )
2019-12-24 09:14:52 +07:00
bootstrapPrintln ( "More details at https://github.com/authelia/authelia/blob/master/docs/getting-started.md" )
2019-10-30 03:54:47 +07:00
}