2019-10-30 03:54:47 +07:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"strings"
|
|
|
|
|
2019-11-02 21:32:58 +07:00
|
|
|
"github.com/clems4ever/authelia/utils"
|
2019-10-30 03:54:47 +07:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
)
|
|
|
|
|
|
|
|
// HostEntry represents an entry in /etc/hosts
|
|
|
|
type HostEntry struct {
|
|
|
|
Domain string
|
|
|
|
IP string
|
|
|
|
}
|
|
|
|
|
|
|
|
var hostEntries = []HostEntry{
|
|
|
|
// For common tests
|
|
|
|
HostEntry{Domain: "login.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "admin.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "singlefactor.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "dev.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "home.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "mx1.mail.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "mx2.mail.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "public.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "secure.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "mail.example.com", IP: "192.168.240.100"},
|
|
|
|
HostEntry{Domain: "duo.example.com", IP: "192.168.240.100"},
|
|
|
|
|
|
|
|
// For Traefik suite
|
|
|
|
HostEntry{Domain: "traefik.example.com", IP: "192.168.240.100"},
|
|
|
|
|
|
|
|
// For testing network ACLs
|
|
|
|
HostEntry{Domain: "proxy-client1.example.com", IP: "192.168.240.201"},
|
|
|
|
HostEntry{Domain: "proxy-client2.example.com", IP: "192.168.240.202"},
|
|
|
|
HostEntry{Domain: "proxy-client3.example.com", IP: "192.168.240.203"},
|
2019-11-16 22:22:10 +07:00
|
|
|
|
|
|
|
// Kubernetes dashboard
|
|
|
|
HostEntry{Domain: "kubernetes.example.com", IP: "192.168.240.110"},
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func installNpmPackages() {
|
|
|
|
runCommand("npm", "ci")
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkCommandExist(cmd string) {
|
|
|
|
fmt.Print("Checking if '" + cmd + "' command is installed...")
|
|
|
|
command := exec.Command("bash", "-c", "command -v "+cmd)
|
|
|
|
err := command.Run()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("[ERROR] You must install " + cmd + " on your machine.")
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(" OK")
|
|
|
|
}
|
|
|
|
|
|
|
|
func installClientNpmPackages() {
|
2019-11-02 21:32:58 +07:00
|
|
|
command := utils.CommandWithStdout("npm", "ci")
|
2019-10-30 03:54:47 +07:00
|
|
|
command.Dir = "client"
|
|
|
|
err := command.Run()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2019-11-07 07:59:24 +07:00
|
|
|
func buildHelperDockerImages() {
|
2019-10-30 03:54:47 +07:00
|
|
|
shell("docker build -t authelia-example-backend example/compose/nginx/backend")
|
|
|
|
shell("docker build -t authelia-duo-api example/compose/duo-api")
|
|
|
|
|
2019-11-02 21:32:58 +07:00
|
|
|
shell("docker-compose -f docker-compose.yml -f example/compose/kind/docker-compose.yml build")
|
|
|
|
shell("docker-compose -f docker-compose.yml -f example/compose/authelia/docker-compose.backend.yml build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)")
|
|
|
|
shell("docker-compose -f docker-compose.yml -f example/compose/authelia/docker-compose.frontend.yml build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)")
|
2019-10-30 03:54:47 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ioutil.WriteFile("/tmp/authelia/hosts", []byte(strings.Join(lines, "\n")), 0644)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if modified {
|
|
|
|
bootstrapPrintln("/etc/hosts needs to be updated")
|
|
|
|
shell("/usr/bin/sudo mv /tmp/authelia/hosts /etc/hosts")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadHostsFile reads the hosts file.
|
|
|
|
func readHostsFile() ([]byte, error) {
|
|
|
|
bs, err := ioutil.ReadFile("/etc/hosts")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
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")
|
|
|
|
readVersion("docker", "--version")
|
|
|
|
readVersion("docker-compose", "--version")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bootstrap bootstrap authelia dev environment
|
|
|
|
func Bootstrap(cobraCmd *cobra.Command, args []string) {
|
|
|
|
bootstrapPrintln("Checking command installation...")
|
|
|
|
checkCommandExist("node")
|
|
|
|
checkCommandExist("docker")
|
|
|
|
checkCommandExist("docker-compose")
|
|
|
|
|
|
|
|
bootstrapPrintln("Getting versions of tools")
|
|
|
|
readVersions()
|
|
|
|
|
2019-11-02 21:32:58 +07:00
|
|
|
bootstrapPrintln("Checking if GOPATH is set")
|
|
|
|
|
|
|
|
goPathFound := false
|
|
|
|
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
|
|
|
bootstrapPrintln("Installing NPM packages for development...")
|
|
|
|
installNpmPackages()
|
|
|
|
|
|
|
|
bootstrapPrintln("Building development Docker images...")
|
2019-11-07 07:59:24 +07:00
|
|
|
buildHelperDockerImages()
|
2019-10-30 03:54:47 +07:00
|
|
|
|
|
|
|
createTemporaryDirectory()
|
|
|
|
|
|
|
|
bootstrapPrintln("Preparing /etc/hosts to serve subdomains of example.com...")
|
|
|
|
prepareHostsFile()
|
|
|
|
|
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-10-30 03:54:47 +07:00
|
|
|
bootstrapPrintln("More details at https://github.com/clems4ever/authelia/blob/master/docs/getting-started.md")
|
|
|
|
}
|