Dear clems4ever,
````
{
"kind": "Ingress",
"apiVersion": "extensions/v1beta1",
"metadata": {
"name": "kibana",
"namespace": "logging",
"annotations": {
"ingress.kubernetes.io/auth-signin": "https://login-dev.example.com",
"ingress.kubernetes.io/auth-url": "https://login-dev.example.com/api/verify",
"ingress.kubernetes.io/force-ssl-redirect": "false",
"ingress.kubernetes.io/proxy-buffer-size": "256k",
"ingress.kubernetes.io/ssl-redirect": "false",
"kubernetes.io/ingress.class": "nginx"
}
},
"spec": {
"rules": [
{
"host": "kibana-dev-ops.example.com",
"http": {
"paths": [
{
"path": "/",
"backend": {
"serviceName": "kibana",
"servicePort": 5601
}
}
]
}
}
]
}
}
````
my ingress is configured as seen here.
````
port: 8080
#
logs_level: debug
#
#
#
totp:
issuer: login-dev.example.com
#
ldap and file.authentication_backend:
ldap:
# The url of the ldap server
url: ldaps://LDAPURL:636
# The base dn for every entries
base_dn: BASEDN
# An additional dn to define the scope to all users
additional_users_dn: ou=People
# The users filter used to find the user DN
# {0} is a matcher replaced by username.
# 'cn={0}' by default.
users_filter: uid={0}
# An additional dn to define the scope of groups
additional_groups_dn: ou=Groups
# The groups filter used for retrieving groups of a given user. [136/9221]
# {0} is a matcher replaced by username.
# {dn} is a matcher replaced by user DN.
# 'member={dn}' by default.
groups_filter: (&(memberUid={0})(objectclass=posixGroup))
# The attribute holding the name of the group
group_name_attribute: cn
# The attribute holding the mail address of the user
mail_attribute: mail
# The username and password of the admin user.
user: LDAPUSER
password: LDAPPASSWORD
#
#
bypass#
#
#
rule is an object with the following keys: domain, subject,policy and resources.#
domain defines which domain or set of domains the rule applies to.#
subject defines the subject to apply authorizations to. This parameter is#
policy is the policy to apply to resources. It must be either bypass,one_factor, two_factor or deny.#
resources is a list of regular expressions that matches a set of resources to#
access_control:
# Default policy can either be bypass, one_factor, two_factor or deny.
# It is the policy applied to any resource if there is no policy to be applied
# to the user.
default_policy: deny
rules: [68/9221]
# Rules applied to everyone
- domain: '*.example.com'
policy: one_factor
# Rules applied to 'admin' group
# Rules applied to 'dev' group
# Rules applied to user 'john'
# Rules applied to user 'harry'
# Rules applied to user 'bob'
#
session:
# The name of the session cookie. (default: authelia_session).
name: authelia_session
# The secret to encrypt the session cookie.
secret: SESSIONSECRET
# The time in ms before the cookie expires and session is reset.
expiration: 3600000 # 1 hour
# The inactivity time in ms before the session is reset.
inactivity: 3600000 # 1 hour
# The domain to protect.
# Note: the authenticator must also be in that domain. If empty, the cookie
# is restricted to the subdomain of the issuer.
domain: example.com
# The redis connection details
redis:
host: authelia-redis-master
port: 6379
password: REDISPASSWORD
#
regulation:
# The number of failed login attempts before user is banned.
# Set it to 0 to disable regulation.
max_retries: 3
# The time range during which the user can attempt login before being banned.
# The user is banned if the authenticaction failed max_retries times in a find_time seconds window.
find_time: 120
# The length of time before a banned user can login again.
ban_time: 300
#
storage:
# The directory where the DB files will be saved
## local:
## path: /var/lib/authelia/store
# Settings to connect to mongo server
mongo:
url: mongodb://mongo-0.mongo:27017,mongo-1.mongo:27017,mongo-2.mongo:27017/?replicaSet=rs0
database: authelia
auth:
username: MONGOUSER
password: MONGOPASSWORD
#
notifier:
# For testing purpose, notifications can be sent in a file
## filesystem:
## filename: /tmp/authelia/notification.txt
# Use your email account to send the notifications. You can use an app password.
# List of valid services can be found here: https://nodemailer.com/smtp/well-known/
## email:
## username: [email protected]
## password: yourpassword
## sender: [email protected]
## service: gmail
# Use a SMTP server for sending notifications
smtp:
#username: test
#password: password
secure: false
host: 'SMTPHOST'
port: 25
sender: EMAIL
````
The login is working in the browser (great job!). But not the probing against Authelia with BasicAuth.
Do You require a specific nginx version?
What could be the reason?
Hello @RafalMaleska , I don't see anything weird in your conf. Can you extract some logs?
Hi @clems4ever , just wanted to provide more information.
As @RafalMaleska said, the login (with LDAP credentials) is working via browser perfectly.
For some cases we need basic auth. For example with curl (or blackbox exporter is also working with basic auth):
curl -u ldapuser https://some-app.example.com
This results in:
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.13.8</center>
</body>
</html>
A curl with -L (follow redirects)
curl -L -u ldapuser https://some-app.example.com
results in:
<!DOCTYPE html><html><head><title>Authelia - 2FA</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="robots" content="noindex, nofollow, nosnippet, noarchive"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:;"><link rel="icon" href="/img/icon.png" type="image/png" sizes="32x32"><link rel="stylesheet" type="text/css" href="/css/authelia.css"></head><body><div class="container"><div class="row"><div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3"><div class="account-wall firstfactor"><div class="row header"><h1>Sign in</h1></div><div class="row body"><div class="form col-xs-10 col-xs-offset-1 col-sm-8 col-sm-offset-2 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"><div class="notification"></div><img class="header-img" src="/img/user.png" alt="user profile"><p>Enter your credentials to sign in</p><form class="form-signin"><div class="form-inputs"><input class="form-control" type="text" id="username" placeholder="Username" required autofocus><input class="form-control" type="password" id="password" placeholder="Password" required></div><button class="btn btn-lg btn-primary btn-block" id="signin" type="submit">Sign in</button><div class="keep-me-logged-in pull-left"><input type="checkbox" id="keep_me_logged_in" name="keep_me_logged_in" value="true"><label for="keep_me_logged_in">Keep me logged in</label></div><div class="bottom-right-links pull-right"><a class="link forgot-password" href="/password-reset/request">Forgot password?</a></div><span class="clearfix"></span></form></div></div><div class="row footer poweredby-block"><div class="poweredby col-xs-6 col-xs-offset-4 col-sm-6 col-sm-offset-4 col-md-6 col-md-offset-4">Powered by <a class="authelia-brand" href="https://github.com/clems4ever/authelia">Authelia</a></div></div></div></div></div></div><script src="/js/authelia.js" type="text/javascript"></script></body></html>%
These curl calls produce the following authelia logs:
debug: date='Tue Mar 05 2019 12:12:27 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='90342486-eddb-4520-b48d-5b9fbb1aa3a6' sessionId='u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt' ip='10.9.104.217' message='Headers = {"host":"login-dev.example.com","connection":"close","x-real-ip":"10.9.104.217","x-forwarded-for":"10.9.104.217","x-forwarded-host":"login-dev.example.com","x-forwarded-port":"443","x-forwarded-proto":"https","x-original-uri":"/api/verify","x-scheme":"https","x-original-forwarded-for":"10.9.104.217, 10.43.151.201","accept-encoding":"gzip","user-agent":"Go-http-client/1.1","x-auth-request-redirect":"/","x-original-method":"GET","x-original-url":"http://some-app.example.com/","x-sent-from":"nginx-ingress-controller"}'
debug: date='Tue Mar 05 2019 12:12:27 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='90342486-eddb-4520-b48d-5b9fbb1aa3a6' sessionId='u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt' ip='10.9.104.217' message='Authentication session u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt was undefined. Resetting.'
error: date='Tue Mar 05 2019 12:12:27 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='90342486-eddb-4520-b48d-5b9fbb1aa3a6' sessionId='u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt' ip='10.9.104.217' message='Reply with error 401: userid is missing'
debug: date='Tue Mar 05 2019 12:12:27 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='90342486-eddb-4520-b48d-5b9fbb1aa3a6' sessionId='u0h5nwD_fHMF4hYorUqJBDuEVIT_aayt' ip='10.9.104.217' message='AccessDeniedError: userid is missing
at BluebirdPromise.resolve.then (/usr/src/server/src/lib/routes/verify/get_session_cookie.js:31:43)
at tryCatcher (/usr/src/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/usr/src/node_modules/bluebird/js/release/promise.js:512:31)
at Promise._settlePromise (/usr/src/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromiseCtx (/usr/src/node_modules/bluebird/js/release/promise.js:606:10)
at _drainQueueStep (/usr/src/node_modules/bluebird/js/release/async.js:142:12)
at _drainQueue (/usr/src/node_modules/bluebird/js/release/async.js:131:9)
at Async._drainQueues (/usr/src/node_modules/bluebird/js/release/async.js:147:5)
at Immediate.Async.drainQueues (/usr/src/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:785:20)
at tryOnImmediate (timers.js:747:5)
at processImmediate [as _immediateCallback] (timers.js:718:5)'
Do you have any ideas?
Hello @RafalMaleska and @dbluxo , I found what's causing your issue. It's because the authorization header to log in basic auth is not Authorization but Proxy-Authorization instead. You need something like
curl -H "Proxy-Authorization: Basic XXXXXXXXXX" https://some-app.example.com.
https://github.com/clems4ever/authelia/blob/f8a12b8482c3a013697e0ed2b616b7fd277146db/server/src/lib/routes/verify/get.ts#L24
https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#Proxy_authentication
What you can do is rewrite the header in nginx to transform Authorization to Proxy-Authorization before sending the query to Authelia.
I'll add more logs in Authelia to make this problem clearer and I'll close the issue afterwards.
Hello @RafalMaleska , @dbluxo , did it solve your issue?
Hi @clems4ever,
we have tried it as you suggested, but without success:
curl -L -H "Proxy-Authorization: Basic XXXXXXXXXXX" https://some-app.example.com
This results in:
<!DOCTYPE html><html><head><title>Authelia - 2FA</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="robots" content="noindex, nofollow, nosnippet, noarchive"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:;"><link rel="icon" href="/img/icon.png" type="image/png" sizes="32x32"><link rel="stylesheet" type="text/css" href="/css/authelia.css"></head><body><div class="container"><div class="row"><div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3"><div class="account-wall firstfactor"><div class="row header"><h1>Sign in</h1></div><div class="row body"><div class="form col-xs-10 col-xs-offset-1 col-sm-8 col-sm-offset-2 col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2"><div class="notification"></div><img class="header-img" src="/img/user.png" alt="user profile"><p>Enter your credentials to sign in</p><form class="form-signin"><div class="form-inputs"><input class="form-control" type="text" id="username" placeholder="Username" required autofocus><input class="form-control" type="password" id="password" placeholder="Password" required></div><button class="btn btn-lg btn-primary btn-block" id="signin" type="submit">Sign in</button><div class="keep-me-logged-in pull-left"><input type="checkbox" id="keep_me_logged_in" name="keep_me_logged_in" value="true"><label for="keep_me_logged_in">Keep me logged in</label></div><div class="bottom-right-links pull-right"><a class="link forgot-password" href="/password-reset/request">Forgot password?</a></div><span class="clearfix"></span></form></div></div><div class="row footer poweredby-block"><div class="poweredby col-xs-6 col-xs-offset-4 col-sm-6 col-sm-offset-4 col-md-6 col-md-offset-4">Powered by <a class="authelia-brand" href="https://github.com/clems4ever/authelia">Authelia</a></div></div></div></div></div></div><script src="/js/authelia.js" type="text/javascript"></script></body></html>
The curl call produce the following authelia logs:
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='292f8a43-60fc-40c8-9769-15b987f9eb61' sessionId='Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM' ip='10.43.151.32' message='Headers = {"host":"login-dev.example.com","connection":"close","x-real-ip":"10.43.151.32","x-forwarded-for":"10.43.151.32","x-forwarded-host":"login-dev.example.com","x-forwarded-port":"443","x-forwarded-proto":"https","x-original-uri":"/api/verify","x-scheme":"https","x-original-forwarded-for":"10.43.151.32, 10.43.150.121","x-amzn-trace-id":"Self=1-5c8778e5-73821c0e1016c14e29430f1a;Root=1-5c8778e5-8b4336d01b1b9a584d6dee68","x-original-url":"http://some-app.example.com/","x-original-method":"GET","x-sent-from":"nginx-ingress-controller","x-auth-request-redirect":"/","user-agent":"curl/7.61.1","accept":"*/*"}'
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='292f8a43-60fc-40c8-9769-15b987f9eb61' sessionId='Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM' ip='10.43.151.32' message='Authentication session Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM was undefined. Resetting.'
error: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='292f8a43-60fc-40c8-9769-15b987f9eb61' sessionId='Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM' ip='10.43.151.32' message='Reply with error 401: userid is missing'
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/api/verify' requestId='292f8a43-60fc-40c8-9769-15b987f9eb61' sessionId='Q1__Rs-spKnLFe46xxdkJkuUxs-58FOM' ip='10.43.151.32' message='AccessDeniedError: userid is missing
at BluebirdPromise.resolve.then (/usr/src/server/src/lib/routes/verify/get_session_cookie.js:31:43)
at tryCatcher (/usr/src/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/usr/src/node_modules/bluebird/js/release/promise.js:512:31)
at Promise._settlePromise (/usr/src/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromiseCtx (/usr/src/node_modules/bluebird/js/release/promise.js:606:10)
at _drainQueueStep (/usr/src/node_modules/bluebird/js/release/async.js:142:12)
at _drainQueue (/usr/src/node_modules/bluebird/js/release/async.js:131:9)
at Async._drainQueues (/usr/src/node_modules/bluebird/js/release/async.js:147:5)
at Immediate.Async.drainQueues (/usr/src/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:785:20)
at tryOnImmediate (timers.js:747:5)
at processImmediate [as _immediateCallback] (timers.js:718:5)'
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/' requestId='07d2bb25-6e1f-416f-a86f-6a61a8219a8c' sessionId='V9E86iWIPeNSbX-igDnXT84dDDQyUMvd' ip='10.43.151.32' message='Headers = {"host":"login-dev.example.com","connection":"close","x-real-ip":"10.43.151.32","x-forwarded-for":"10.43.151.32","x-forwarded-host":"login-dev.example.com","x-forwarded-port":"443","x-forwarded-proto":"https","x-original-uri":"/?rd=https://some-app.example.com/","x-scheme":"https","x-original-forwarded-for":"10.43.151.32","x-amzn-trace-id":"Root=1-5c8778e5-ee81ee28b7a6c317373cc391","user-agent":"curl/7.61.1","accept":"*/*"}'
debug: date='Tue Mar 12 2019 09:16:21 GMT+0000 (UTC)' method='GET', path='/' requestId='07d2bb25-6e1f-416f-a86f-6a61a8219a8c' sessionId='V9E86iWIPeNSbX-igDnXT84dDDQyUMvd' ip='10.43.151.32' message='Authentication session V9E86iWIPeNSbX-igDnXT84dDDQyUMvd was undefined. Resetting.'
We have deployed nginx-ingress-controller and all ingresses as you described in your example for kubernetes:
https://github.com/clems4ever/authelia/tree/master/example/kube
Any further ideas?
Hi @clems4ever,
we figured out that the problem was at the Nginx Ingress Controller in Kubernetes.
There are two settings in the Nginx Ingress Controller we have to configure in the official Helm-Chart (https://github.com/helm/charts/tree/master/stable/nginx-ingress).
With Nginx Ingress Controller > 0.21.0 we have to set:
controller:
config:
proxy-real-ip-cidr: "0.0.0.0/0"
use-forwarded-headers: "true"
headers:
Proxy-Authorization: $http_authorization
With Nginx Ingress Controller <= 0.21.0 we only have to set:
controller:
headers:
Proxy-Authorization: $http_authorization
Now basic-auth with Nginx Ingress Controller in Kubernetes is working as expected.
Thank you for the great work.
Wow, interesting! I will certainly include this in a doc somewhere.
Thanks for giving back your investigation results!
Most helpful comment
Hi @clems4ever,
we figured out that the problem was at the Nginx Ingress Controller in Kubernetes.
There are two settings in the Nginx Ingress Controller we have to configure in the official Helm-Chart (https://github.com/helm/charts/tree/master/stable/nginx-ingress).
With Nginx Ingress Controller > 0.21.0 we have to set:
With Nginx Ingress Controller <= 0.21.0 we only have to set:
Now basic-auth with Nginx Ingress Controller in Kubernetes is working as expected.
Thank you for the great work.