From 7dc4ac5cd9a5646b4a0daea593ec42e0ff6c452c Mon Sep 17 00:00:00 2001 From: Amir Zarrinkafsh Date: Fri, 10 Jan 2020 15:49:30 +1100 Subject: [PATCH] Create a suite for HAProxy --- cmd/authelia-scripts/cmd_bootstrap.go | 3 ++ example/compose/haproxy/Dockerfile | 11 ++++ example/compose/haproxy/docker-compose.yml | 10 ++++ example/compose/haproxy/haproxy.cfg | 54 ++++++++++++++++++++ example/compose/traefik/docker-compose.yml | 2 +- internal/suites/HAProxy/configuration.yml | 41 +++++++++++++++ internal/suites/HAProxy/docker-compose.yml | 6 +++ internal/suites/HAProxy/users.yml | 29 +++++++++++ internal/suites/suite_haproxy.go | 59 ++++++++++++++++++++++ internal/suites/suite_haproxy_test.go | 27 ++++++++++ 10 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 example/compose/haproxy/Dockerfile create mode 100644 example/compose/haproxy/docker-compose.yml create mode 100644 example/compose/haproxy/haproxy.cfg create mode 100644 internal/suites/HAProxy/configuration.yml create mode 100644 internal/suites/HAProxy/docker-compose.yml create mode 100644 internal/suites/HAProxy/users.yml create mode 100644 internal/suites/suite_haproxy.go create mode 100644 internal/suites/suite_haproxy_test.go diff --git a/cmd/authelia-scripts/cmd_bootstrap.go b/cmd/authelia-scripts/cmd_bootstrap.go index f17524dbb..6e9cbd3b0 100644 --- a/cmd/authelia-scripts/cmd_bootstrap.go +++ b/cmd/authelia-scripts/cmd_bootstrap.go @@ -37,6 +37,9 @@ var hostEntries = []HostEntry{ // For Traefik suite HostEntry{Domain: "traefik.example.com", IP: "192.168.240.100"}, + // For HAProxy suite + HostEntry{Domain: "haproxy.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"}, diff --git a/example/compose/haproxy/Dockerfile b/example/compose/haproxy/Dockerfile new file mode 100644 index 000000000..56b928823 --- /dev/null +++ b/example/compose/haproxy/Dockerfile @@ -0,0 +1,11 @@ +FROM haproxy:2.1-alpine + +RUN \ +apk add --no-cache \ + curl \ + lua5.3-socket \ + openssl && \ +curl -Lfs -o /usr/local/etc/haproxy/auth-request.lua "https://raw.githubusercontent.com/TimWolla/haproxy-auth-request/master/auth-request.lua" && \ +sed -i 's/HEAD/GET/g' /usr/local/etc/haproxy/auth-request.lua && \ +openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=AU/ST=Victoria/L=Melbourne/O=Authelia/CN=*.example.com" -keyout haproxy.key -out haproxy.crt && \ +cat haproxy.key haproxy.crt > /usr/local/etc/haproxy/haproxy.pem \ No newline at end of file diff --git a/example/compose/haproxy/docker-compose.yml b/example/compose/haproxy/docker-compose.yml new file mode 100644 index 000000000..35d97c568 --- /dev/null +++ b/example/compose/haproxy/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3' +services: + haproxy: + build: ./example/compose/haproxy/ + volumes: + - ./example/compose/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg + networks: + authelianet: + # Set the IP to be able to query on port 8080 + ipv4_address: 192.168.240.100 \ No newline at end of file diff --git a/example/compose/haproxy/haproxy.cfg b/example/compose/haproxy/haproxy.cfg new file mode 100644 index 000000000..705d91b25 --- /dev/null +++ b/example/compose/haproxy/haproxy.cfg @@ -0,0 +1,54 @@ +global + lua-load /usr/local/etc/haproxy/auth-request.lua + log stdout format raw local0 debug + +defaults + mode http + log global + option httplog + option forwardfor + +frontend fe_api + bind *:8081 ssl crt /usr/local/etc/haproxy/haproxy.pem + + stats enable + stats uri /api + stats refresh 10s + stats admin if LOCALHOST + +frontend fe_http + bind *:8080 ssl crt /usr/local/etc/haproxy/haproxy.pem + + acl host-authelia-portal hdr(host) -i login.example.com:8080 + acl api-path path_beg -i /api + acl protected-frontends hdr(host) -m reg -i ^(admin|home|public|secure|singlefactor)\.example\.com + + http-request set-var(req.scheme) str(https) if { ssl_fc } + http-request set-var(req.scheme) str(http) if !{ ssl_fc } + http-request set-var(req.questionmark) str(?) if { query -m found } + + http-request set-header X-Real-IP %[src] + http-request set-header X-Forwarded-Proto %[var(req.scheme)] + http-request set-header X-Forwarded-Host %[req.hdr(Host)] + http-request add-header X-Forwarded-Port %[dst_port] + http-request set-header X-Forwarded-Uri %[path]%[var(req.questionmark)]%[query] + + http-request lua.auth-request be_authelia /api/verify if protected-frontends + + use_backend be_authelia if host-authelia-portal api-path + use_backend fe_authelia if host-authelia-portal !api-path + use_backend be_authelia if protected-frontends !{ var(txn.auth_response_successful) -m bool } + use_backend be_protected if protected-frontends + use_backend be_mail if { hdr(host) -i mail.example.com:8080 } + +backend be_authelia + server authelia-backend authelia-backend:9091 + +backend fe_authelia + server authelia-frontend authelia-frontend:3000 + +backend be_mail + server smtp-backend smtp:1080 + +backend be_protected + server nginx-backend nginx-backend:80 \ No newline at end of file diff --git a/example/compose/traefik/docker-compose.yml b/example/compose/traefik/docker-compose.yml index f06460713..eff0bcfa2 100644 --- a/example/compose/traefik/docker-compose.yml +++ b/example/compose/traefik/docker-compose.yml @@ -10,5 +10,5 @@ services: - traefik.port=8081 networks: authelianet: - # Set the IP to be able to query on port 443 + # Set the IP to be able to query on port 8080 ipv4_address: 192.168.240.100 \ No newline at end of file diff --git a/internal/suites/HAProxy/configuration.yml b/internal/suites/HAProxy/configuration.yml new file mode 100644 index 000000000..201d95459 --- /dev/null +++ b/internal/suites/HAProxy/configuration.yml @@ -0,0 +1,41 @@ +############################################################### +# Authelia minimal configuration # +############################################################### + +port: 9091 + +logs_level: debug + +jwt_secret: unsecure_secret + +authentication_backend: + file: + path: /var/lib/authelia/users.yml + +session: + secret: unsecure_session_secret + domain: example.com + expiration: 3600 # 1 hour + inactivity: 300 # 5 minutes + +storage: + local: + path: /var/lib/authelia/db.sqlite + +access_control: + default_policy: bypass + rules: + - domain: "public.example.com" + policy: bypass + - domain: "admin.example.com" + policy: two_factor + - domain: "secure.example.com" + policy: two_factor + - domain: "singlefactor.example.com" + policy: one_factor + +notifier: + smtp: + host: smtp + port: 1025 + sender: admin@example.com diff --git a/internal/suites/HAProxy/docker-compose.yml b/internal/suites/HAProxy/docker-compose.yml new file mode 100644 index 000000000..eb4ea22e7 --- /dev/null +++ b/internal/suites/HAProxy/docker-compose.yml @@ -0,0 +1,6 @@ +version: "3" +services: + authelia-backend: + volumes: + - "./internal/suites/HAProxy/configuration.yml:/etc/authelia/configuration.yml:ro" + - "./internal/suites/HAProxy/users.yml:/var/lib/authelia/users.yml" diff --git a/internal/suites/HAProxy/users.yml b/internal/suites/HAProxy/users.yml new file mode 100644 index 000000000..6fe7a384d --- /dev/null +++ b/internal/suites/HAProxy/users.yml @@ -0,0 +1,29 @@ +############################################################### +# Users Database # +############################################################### + +# This file can be used if you do not have an LDAP set up. + +# List of users +users: + john: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: john.doe@authelia.com + groups: + - admins + - dev + + harry: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: harry.potter@authelia.com + groups: [] + + bob: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: bob.dylan@authelia.com + groups: + - dev + + james: + password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/" + email: james.dean@authelia.com \ No newline at end of file diff --git a/internal/suites/suite_haproxy.go b/internal/suites/suite_haproxy.go new file mode 100644 index 000000000..f3aea69af --- /dev/null +++ b/internal/suites/suite_haproxy.go @@ -0,0 +1,59 @@ +package suites + +import ( + "fmt" + "time" +) + +var haproxySuiteName = "HAProxy" + +func init() { + dockerEnvironment := NewDockerEnvironment([]string{ + "docker-compose.yml", + "internal/suites/HAProxy/docker-compose.yml", + "example/compose/authelia/docker-compose.backend.yml", + "example/compose/authelia/docker-compose.frontend.yml", + "example/compose/nginx/backend/docker-compose.yml", + "example/compose/haproxy/docker-compose.yml", + "example/compose/smtp/docker-compose.yml", + }) + + setup := func(suitePath string) error { + err := dockerEnvironment.Up() + + if err != nil { + return err + } + + return waitUntilAutheliaIsReady(dockerEnvironment) + } + + onSetupTimeout := func() error { + backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil) + if err != nil { + return err + } + fmt.Println(backendLogs) + + frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil) + if err != nil { + return err + } + fmt.Println(frontendLogs) + return nil + } + + teardown := func(suitePath string) error { + err := dockerEnvironment.Down() + return err + } + + GlobalRegistry.Register(haproxySuiteName, Suite{ + SetUp: setup, + SetUpTimeout: 5 * time.Minute, + OnSetupTimeout: onSetupTimeout, + TestTimeout: 2 * time.Minute, + TearDown: teardown, + TearDownTimeout: 2 * time.Minute, + }) +} diff --git a/internal/suites/suite_haproxy_test.go b/internal/suites/suite_haproxy_test.go new file mode 100644 index 000000000..800dd639f --- /dev/null +++ b/internal/suites/suite_haproxy_test.go @@ -0,0 +1,27 @@ +package suites + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +type HAProxySuite struct { + *SeleniumSuite +} + +func NewHAProxySuite() *HAProxySuite { + return &HAProxySuite{SeleniumSuite: new(SeleniumSuite)} +} + +func (s *HAProxySuite) TestOneFactorScenario() { + suite.Run(s.T(), NewOneFactorScenario()) +} + +func (s *HAProxySuite) TestTwoFactorScenario() { + suite.Run(s.T(), NewTwoFactorScenario()) +} + +func TestHAProxySuite(t *testing.T) { + suite.Run(t, NewHAProxySuite()) +}