diff --git a/.gitignore b/.gitignore index e9fe0ab29..43c1931fd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,9 +13,7 @@ src/.baseDir.ts *.swp -*.sh - -config.yml +/config.yml npm-debug.log diff --git a/.travis.yml b/.travis.yml index a0ec104ff..b5052c4fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,14 +19,7 @@ addons: before_install: npm install -g npm@'>=2.13.5' script: -- grunt build-dist -- grunt docker-build -- docker-compose build -- docker-compose up -d -- sleep 5 -- ./scripts/check-services.sh -- npm run int-test -- ./scripts/npm-deployment-test.sh + - ./scripts/travis.sh after_success: - ./scripts/docker-publish.sh diff --git a/Dockerfile b/Dockerfile index aec7ddcfd..63b6d3eb4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ COPY dist/src/server /usr/src ENV PORT=80 EXPOSE 80 -VOLUME /etc/auth-server -VOLUME /var/lib/auth-server +VOLUME /etc/authelia +VOLUME /var/lib/authelia -CMD ["node", "index.js", "/etc/auth-server/config.yml"] +CMD ["node", "index.js", "/etc/authelia/config.yml"] diff --git a/Gruntfile.js b/Gruntfile.js index 654f5f7c6..775c85d38 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -5,12 +5,12 @@ module.exports = function (grunt) { run: { options: {}, "build": { - cmd: "npm", - args: ['run', 'build'] + cmd: "./node_modules/.bin/tsc", + args: ['-p', 'tsconfig.json'] }, "tslint": { - cmd: "npm", - args: ['run', 'tslint'] + cmd: "./node_modules/.bin/tslint", + args: ['-c', 'tslint.json', '-p', 'tsconfig.json'] }, "test": { cmd: "npm", diff --git a/README.md b/README.md index 13f9969c1..450c71060 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Build](https://travis-ci.org/clems4ever/authelia.svg?branch=master)](https://travis-ci.org/clems4ever/authelia) **Authelia** is a complete HTTP 2-factor authentication server for proxies like -nginx. It has been made to work with NGINX auth_request module and is currently +nginx. It has been made to work with nginx [auth_request] module and is currently used in production to secure internal services in a small docker swarm cluster. ## Features @@ -17,25 +17,53 @@ address. ## Deployment -If you don't have any LDAP and nginx setup yet, I advise you to follow the -Getting Started. That way, you will not require anything to start. +If you don't have any LDAP and/or nginx setup yet, I advise you to follow the +[Getting Started](#Getting-started) section. That way, you can test it right away +without even configure anything. -Otherwise here are the available steps to deploy on your machine. +Otherwise here are the available steps to deploy **Authelia** on your machine given +your configuration file is **/path/to/your/config.yml**. ### With NPM npm install -g authelia + authelia /path/to/your/config.yml ### With Docker docker pull clems4ever/authelia + docker run -v /path/to/your/config.yml:/etc/authelia/config.yml -v /path/to/data/dir:/var/lib/authelia clems4ever/authelia + +where **/path/to/data/dir** is the directory where all user data will be stored. ## Getting started The provided example is docker-based so that you can deploy and test it very -quickly. First clone the repo make sure you don't have anything listening on -port 8080 before starting. -Add the following lines to your /etc/hosts to simulate multiple subdomains +quickly. + +### Pre-requisites + +#### npm +Make sure you have npm and node installed on your computer. + +#### Docker +Make sure you have **docker** and **docker-compose** installed on your machine. +For your information, here are the versions that have been used for testing: + + docker --version + +gave *Docker version 17.03.1-ce, build c6d412e*. + + docker-compose --version + +gave *docker-compose version 1.14.0, build c7bdf9e*. + +#### Available port +Make sure you don't have anything listening on port 8080. + +#### Subdomain aliases + +Add the following lines to your **/etc/hosts** to alias multiple subdomains so that nginx can redirect request to the correct virtual host. 127.0.0.1 secret.test.local 127.0.0.1 secret1.test.local @@ -44,23 +72,28 @@ Add the following lines to your /etc/hosts to simulate multiple subdomains 127.0.0.1 mx1.mail.test.local 127.0.0.1 mx2.mail.test.local 127.0.0.1 auth.test.local + +### Deployment -Then, type the following command to build and deploy the services: +Deploy **Authelia** example with the following command: npm install --only=dev - grunt build-dist - docker-compose build - docker-compose up -d + ./node_modules/.bin/grunt build-dist + ./scripts/deploy-example.sh After few seconds the services should be running and you should be able to visit -[https://home.test.local:8080/](https://home.test.local:8080/). +[https://home.test.local:8080/](https://home.test.local:8080/). -Normally, a self-signed certificate exception should appear, it has to be -accepted before getting to the login page: +When accessing the login page, a self-signed certificate exception should appear, +it has to be trusted before you can get to the target page. The certificate +must be trusted for each subdomain, therefore it is normal to see the exception + several times. + +Below is what the login page looks like: -### 1st factor: LDAP and ACL +### First factor: LDAP and ACL An LDAP server has been deployed for you with the following credentials and access control list: @@ -76,54 +109,55 @@ any subdomain. - [secret1.test.local](https://secret1.test.local:8080/secret.html) - [home.test.local](https://home.test.local:8080/secret.html) -Type them in the login page and validate. Then, the second factor page should -have appeared as shown below. +You can use them in the login page. If everything is ok, the second factor +page should appear as shown below. Otherwise you'll get an error message notifying +your credentials are wrong. -### 2nd factor: TOTP (Time-Base One Time Password) +### Second factor: TOTP (Time-Base One Time Password) In **Authelia**, you need to register a per user TOTP secret before authenticating. To do that, you need to click on the register button. It will send a link to the user email address. Since this is an example, no email will be sent, the link is rather delivered in the file -./notifications/notification.txt. Paste the link in your browser and you'll get +**./notifications/notification.txt**. Paste the link in your browser and you'll get your secret in QRCode and Base32 formats. You can use -[Google Authenticator](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en) -to store them and get the generated tokens required during authentication. +[Google Authenticator] +to store them and get the generated tokens with the app. ### 2nd factor: U2F (Universal 2-Factor) with security keys **Authelia** also offers authentication using U2F devices like [Yubikey](Yubikey) USB security keys. U2F is one of the most secure authentication protocol and is -already available for accounts on Google, Facebook, Github and more. +already available for Google, Facebook, Github accounts and more. -Like TOTP, U2F requires you register your security key before authenticating -with it. To do so, click on the register button. This will send a link to the +Like TOTP, U2F requires you register your security key before authenticating. +To do so, click on the register button. This will send a link to the user email address. Since this is an example, no email will be sent, the -link is rather delivered in the file ./notifications/notification.txt. Paste +link is rather delivered in the file **./notifications/notification.txt**. Paste the link in your browser and you'll be asking to touch the token of your device -to register it. You can now authenticate using your U2F device by simply -touching the token. +to register. Upon successful registration, you can authenticate using your U2F +device by simply touching the token. Easy, right?! ### Password reset With **Authelia**, you can also reset your password in no time. Click on the -according button in the login page, provide the username of the user requiring +**Forgot password?** link in the login page, provide the username of the user requiring a password reset and **Authelia** will send an email with an link to the user email address. For the sake of the example, the email is delivered in the file -./notifications/notification.txt. +**./notifications/notification.txt**. Paste the link in your browser and you should be able to reset the password. ### Access Control With **Authelia**, you can define your own access control rules for restricting -the access to certain subdomains to your users. Those rules are defined in the -configuration file and can be either default, per-user or per-group policies. +the user access to some subdomains. Those rules are defined in the +configuration file and can be set either for everyone, per-user or per-group policies. Check out the *config.template.yml* to see how they are defined. ## Documentation @@ -172,4 +206,6 @@ Follow [contributing](CONTRIBUTORS.md) file. [TOTP]: https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm [U2F]: https://www.yubico.com/about/background/fido/ [Yubikey]: https://www.yubico.com/products/yubikey-hardware/yubikey4/ +[auth_request]: http://nginx.org/en/docs/http/ngx_http_auth_request_module.html +[Google Authenticator]: https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en diff --git a/config.template.yml b/config.template.yml index 2b234c111..acff13626 100644 --- a/config.template.yml +++ b/config.template.yml @@ -12,7 +12,7 @@ logs_level: info # Example: for user john, the DN will be cn=john,ou=users,dc=example,dc=com ldap: # The url of the ldap server - url: ldap://ldap + url: ldap://openldap-restriction # The base dn for every entries base_dn: dc=example,dc=com @@ -85,7 +85,7 @@ store_directory: /var/lib/authelia/store notifier: # For testing purpose, notifications can be sent in a file filesystem: - filename: /var/lib/auth-server/notifications/notification.txt + filename: /var/lib/authelia/notifications/notification.txt # Use your gmail account to send the notifications. You can use an app password. # gmail: diff --git a/docker-compose.base.yml b/docker-compose.base.yml new file mode 100644 index 000000000..3432395ad --- /dev/null +++ b/docker-compose.base.yml @@ -0,0 +1,5 @@ +version: '2' + +networks: + example-network: + driver: bridge diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 79b5208b5..6f48df1f4 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,17 +1,10 @@ - version: '2' services: - auth: + authelia: volumes: - ./test:/usr/src/test - ./dist/src/server:/usr/src - ./node_modules:/usr/src/node_modules - - ./config.yml:/etc/auth-server/config.yml:ro - - ldap-admin: - image: osixia/phpldapadmin:0.6.11 - ports: - - 9090:80 - environment: - - PHPLDAPADMIN_LDAP_HOSTS=ldap - - PHPLDAPADMIN_HTTPS=false + - ./config.yml:/etc/authelia/config.yml:ro + networks: + - example-network diff --git a/docker-compose.yml b/docker-compose.yml index bfaaeb331..deee95c9b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,37 +1,11 @@ - version: '2' services: - auth: + authelia: build: . - depends_on: - - ldap restart: always volumes: - - ./config.template.yml:/etc/auth-server/config.yml:ro - - ./notifications:/var/lib/auth-server/notifications + - ./config.template.yml:/etc/authelia/config.yml:ro + - ./notifications:/var/lib/authelia/notifications + networks: + - example-network - ldap: - image: dinkel/openldap - environment: - - SLAPD_ORGANISATION=MyCompany - - SLAPD_DOMAIN=example.com - - SLAPD_PASSWORD=password - - SLAPD_ADDITIONAL_MODULES=memberof - - SLAPD_ADDITIONAL_SCHEMAS=openldap - - SLAPD_FORCE_RECONFIGURE=true - expose: - - "389" - volumes: - - ./example/ldap:/etc/ldap.dist/prepopulate - - nginx: - image: nginx:alpine - volumes: - - ./example/nginx_conf/nginx.conf:/etc/nginx/nginx.conf - - ./example/nginx_conf/index.html:/usr/share/nginx/html/index.html - - ./example/nginx_conf/secret.html:/usr/share/nginx/html/secret.html - - ./example/nginx_conf/ssl:/etc/ssl - depends_on: - - auth - ports: - - "8080:443" diff --git a/example/ldap/Dockerfile b/example/ldap/Dockerfile new file mode 100644 index 000000000..fbb515eba --- /dev/null +++ b/example/ldap/Dockerfile @@ -0,0 +1,9 @@ +FROM clems4ever/openldap + +ENV SLAPD_ORGANISATION=MyCompany +ENV SLAPD_DOMAIN=example.com +ENV SLAPD_PASSWORD=password +ENV SLAPD_CONFIG_PASSWORD=password +ENV SLAPD_ADDITIONAL_MODULES=memberof +ENV SLAPD_ADDITIONAL_SCHEMAS=openldap +ENV SLAPD_FORCE_RECONFIGURE=true diff --git a/example/ldap/access.rules b/example/ldap/access.rules new file mode 100644 index 000000000..125b4ce9a --- /dev/null +++ b/example/ldap/access.rules @@ -0,0 +1,4 @@ +olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymou + s auth by * none +# olcAccess: {1}to dn.base="" by * read +# olcAccess: {2}to * by * read diff --git a/example/ldap/base.ldif b/example/ldap/base.ldif index 97ca0356d..f1fbdb887 100644 --- a/example/ldap/base.ldif +++ b/example/ldap/base.ldif @@ -25,7 +25,7 @@ dn: cn=john,ou=users,dc=example,dc=com cn: john objectclass: inetOrgPerson objectclass: top -mail: clement.michaud34@gmail.com +mail: john.doe@example.com sn: John Doe userpassword: {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g= @@ -45,18 +45,3 @@ mail: bob.dylan@example.com sn: Bob Dylan userpassword: {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g= -# dn: uid=jack,ou=users,dc=example,dc=com -# cn: jack -# gidnumber: 501 -# givenname: Jack -# homedirectory: /home/jack -# loginshell: /bin/sh -# objectclass: inetOrgPerson -# objectclass: posixAccount -# objectclass: top -# mail: jack.daniels@example.com -# sn: Jack Daniels -# uid: jack -# uidnumber: 1001 -# userpassword: {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g= -# diff --git a/example/ldap/docker-compose.admin.yml b/example/ldap/docker-compose.admin.yml new file mode 100644 index 000000000..c73075782 --- /dev/null +++ b/example/ldap/docker-compose.admin.yml @@ -0,0 +1,11 @@ +version: '2' +services: + openldap-admin: + image: osixia/phpldapadmin:0.6.11 + ports: + - 9090:80 + environment: + - PHPLDAPADMIN_LDAP_HOSTS=openldap + - PHPLDAPADMIN_HTTPS=false + networks: + - example-network diff --git a/example/ldap/docker-compose.yml b/example/ldap/docker-compose.yml new file mode 100644 index 000000000..0f505a0a1 --- /dev/null +++ b/example/ldap/docker-compose.yml @@ -0,0 +1,10 @@ +version: '2' +services: + openldap: + build: ./example/ldap + volumes: + - ./example/ldap/base.ldif:/etc/ldap.dist/prepopulate/base.ldif + - ./example/ldap/access.rules:/etc/ldap.dist/prepopulate/access.rules + networks: + - example-network + diff --git a/example/nginx/docker-compose.yml b/example/nginx/docker-compose.yml new file mode 100644 index 000000000..f41273779 --- /dev/null +++ b/example/nginx/docker-compose.yml @@ -0,0 +1,24 @@ +version: '2' +services: + nginx: + image: nginx:alpine + volumes: + - ./example/nginx/index.html:/usr/share/nginx/html/index.html + - ./example/nginx/secret.html:/usr/share/nginx/html/secret.html + - ./example/nginx/ssl:/etc/ssl + - ./example/nginx/nginx.conf:/etc/nginx/nginx.conf + ports: + - "8080:443" + depends_on: + - authelia + networks: + example-network: + aliases: + - home.test.local + - secret.test.local + - secret1.test.local + - secret2.test.local + - mx1.mail.test.local + - mx2.mail.test.local + - auth.test.local + diff --git a/example/nginx_conf/index.html b/example/nginx/index.html similarity index 100% rename from example/nginx_conf/index.html rename to example/nginx/index.html diff --git a/example/nginx_conf/nginx.conf b/example/nginx/nginx.conf similarity index 95% rename from example/nginx_conf/nginx.conf rename to example/nginx/nginx.conf index 400eb115b..bb0749f34 100644 --- a/example/nginx_conf/nginx.conf +++ b/example/nginx/nginx.conf @@ -36,7 +36,7 @@ http { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; - proxy_pass http://auth/; + proxy_pass http://authelia/; proxy_intercept_errors on; @@ -68,7 +68,7 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $http_host; - proxy_pass http://auth/verify; + proxy_pass http://authelia/verify; } location = /secret.html { diff --git a/example/nginx_conf/secret.html b/example/nginx/secret.html similarity index 63% rename from example/nginx_conf/secret.html rename to example/nginx/secret.html index 8b44155a9..d16936783 100644 --- a/example/nginx_conf/secret.html +++ b/example/nginx/secret.html @@ -4,6 +4,6 @@
This is a very important secret!