Sentry LDAP config

Hi,

For my employer I’ve had to set up a Sentry instance with LDAP auth. It was not easy and fun as for some reason I couldn’t get the service to log errors.

I’ve had a few challanges:

– Non english letters (any string with those was changed into a base64 code),
– SSL connection with the domain controller (if you won’t used you’ll be able to see the password of the authorized user),

I’ll post the raw LDAP section of the config on my github account. Here I’ll explain the most important sections of the config.

######################
## django-auth-ldap ##
######################

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType

ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3);

This is one of the most important lines IMO. Thanks to the usage of LDAPv3 protocol it’s apparently much easier to handle base64 strings. It’s useful if you have users with non-english letters in their names/2nd names/usernames

AUTH_LDAP_SERVER_URI = 'ldaps://ad.wizard.net'

If you use ldap you’ll connect to port 389. If you use ldaps (with ssl, like https) you’ll connect to port 636.

ldap.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND)
ldap.set_option(ldap.OPT_X_TLS_DEMAND, True)

This section is like super-important if you use SSL. Thanks to pages like:
https://www.programcreek.com/python/example/3016/ldap.SCOPE_SUBTREE
https://www.python-ldap.org/en/latest/reference/ldap.html

and most important https://helpful.knobs-dials.com/index.php/Python-ldap_notes
I was able to figure out how to set this up and running.

AUTH_LDAP_BIND_DN = "CN=sentry,OU=TechACC,DC=ad,DC=wizard,DC=net"
AUTH_LDAP_BIND_PASSWORD = "YOUR_PASSWORD"

We use this account to connect to LDAP and send request about users.

AUTH_LDAP_USER_SEARCH = LDAPSearch(
'OU=Users,DC=ad,DC=wizard,DC=net',
ldap.SCOPE_SUBTREE,
'(sAMAccountName=%(user)s)',
)

This is where we will be searching for the users.

AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
'ou=Permissions,ou=wizard,DC=ad,DC=wizard,DC=net',
ldap.SCOPE_SUBTREE,
'(objectClass=group)'
)

This is where we will be searching for the required groups.

AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr='mail')

Describes type of group returned by AUTH_LDAP_GROUP_SEARCH.

AUTH_LDAP_SENTRY_USERNAME_FIELD = 'sAMAccountName'

Here we specify which AD field will be used as username.

AUTH_LDAP_REQUIRE_GROUP = 'CN=sentry-users,OU=Permissions,OU=wizard,DC=ad,DC=wizard,DC=net'

The group required to be authorized to log into Sentry.

AUTH_LDAP_USER_ATTR_MAP = {
'name': 'sAMAccountName',
'username': 'sAMAccountName',
'email': 'mail'
}

A map of fields that should be assigned from AD to Sentry.

AUTH_LDAP_DEFAULT_SENTRY_ORGANIZATION = u'Sentry'

If you have a single organization (as I do) you can add this line, or choose a default one before assigning the user to other organizations.

AUTH_LDAP_SENTRY_ORGANIZATION_ROLE_TYPE = 'member'

The default role for the logged in user after using LDAP.

AUTHENTICATION_BACKENDS = AUTHENTICATION_BACKENDS + (
'sentry_ldap_auth.backend.SentryLdapBackend',
'django.contrib.auth.backends.ModelBackend',
)

If you have both – local and AD authorized accounts we can set the section as above.
You just insert two (or more, as you can authorize via other services too) auth backends. Here I have chosen a local backend (django.contrib.auth.blablabla) which refers to the users created / invited / registered and a sentry_ldap_auth.backend, which I hope I don’t have to explain.

 

I hope that this post helps people out there with sentry-ldap-auth on Sentry (this one works with 8.22 and 9.00).

A thing worth mentioning that on Sentry 9.00 I’ve used


pip install django-auth-ldap==1.2.13 python-ldap sentry-ldap-auth

 

 

That’s all… I hope.

 

Cheers,

Wizard

Advertisements

Sentry via ansible

Hi all,

Today’s story is about Sentry. I’ve prepared a ansible playbook for Debian and CentOS, so I can learn a bit of both – Sentry and Ansible.

The playbook is available on my github account – https://github.com/thewizardlog/sentry-ansible

The whole idea is to install sentry with as little effort as possible. I guess I’ve managed to do it.

All the instructions are mentioned in the README section on github.
Hope it’s going to help someone.

Cheers,
Wizard

Force10 switch

Hi ya!

In todays  episode, Wizard:
1) Is buying an old Force10 switch
2) Finds out that he has no console cable
3) Creates the cable with his terrible soldering skills
4) Resets the whole config to default

1) Wizard is buying an old Force10 switch

I’ve spoke to a bloke from the datacenter at work if we have any switches that are planned to be thrown away. He found me a Force10 SA-01-GE-48T.
It’s been running in the datacenter for ages, but it’s working. Enough for my needs. As you can guess from the name – it’s a 48 port gigabit switch. It has also four (4) slots for SFP. Pretty nice.

2) Finds out that he has no console cable

I also spoke to the chap if he has any console cables. Heard that it’s a problem. So I googled a bit.
On Force10 site:
“Note: Force10 Networks’ C-Series and E-Series and many other vendor’s switches use a rolled (crossover cable) for a console connection. These cables will not work with an S-Series.”

That didin’t sound good. Like normally I could have used a cisco cable, but not in this case. I could use an adapter, but had neither at home.

Finally found a thread on reddit (Clicky!) with a very important information:
“EDIT: Switching the 3 and 6 pin cables worked” which was a very useful information.

3) Creates the cable with his terrible soldering skills

I’ve searched more for a standard Force10 S-series cable wiring diagram. Didin’t really find it. But the info from reddit came in handy. I’ve found this
snapav-db9-f-rj45-adpt-xl3 which clarified a bit how to read the diagrams and was a nice starting point.
Finally, thanks to: https://www.wti.com/t-port-cable-pinouts.aspx and https://www.wti.com/p-236-72-3383-01-cisco-rollover-console-cable-blue-db9-to-rj45-6.aspx I’ve managed to create my own cable.

I’ve used what I’ve had at home:
– soldering iron
– solder
– db9 aka rs232 connector
– rj45 cable
– usb to rs232 adapter
So we have the wiring diagram for Cisco console cable:
72-3383-01-pinout-300

If you remember about the reddit post: “Switching the 3 and 6 pin cables worked” than all we need to do is change it on either side to make it work.
I’ve cut off one end of the rj45 and soldered everything. Remember about looking on the numbers that are provided on the db9 connector. I’ve soldered 5th pin of DB9 with GND using a leg from some electronic part.

After that I’ve connected it to the rs232 adapter and voila’

Photo-2018-08-28-00-43-41_0046

 

Next step is connecting to the switch. I’ve used putty for that. The data is provided and it’s a standard procedure: https://www.force10networks.com/CSPortal20/TechTips/0055_HowDoILoginToTheConsole.aspx
Remember that putty under Linux by default chooses a /dev/ttyS0 device. If you are using an USB adapter than you have to change it to /dev/ttyUSB0 and pick serial connection.
Put the other side of the cable into the console port and start the switch. If everything has been done correctly than you should see the switch booting up.

But hmm…

4) Resets the whole config to default
It turns out that the config was not cleaned and I don’t know the password for the switch. Ok, let’s give it a try.
Or like 20 tries before I’ve got it right: https://www.force10networks.com/CSPortal20/TechTips/0047_HowToResetS-SeriesToFactoryDefaults.aspx
Now here we need to be fast. But everything is in the manual. My menu was with a newer version so I’ve had to press “10” instead of “9” to reset defaults.
After resetting the switch from the console – voila, default user and password worked and I have my own Force10 switch for my little home datacenter.

Just FYI: It takes about 80W without anything connected.

So yeah, fun evening.

Cheers,

Wizard

Nginx throttling

Recently I’ve noticed that someone is trying to brute-force the login to one of my services. At that time I’ve had no captcha on login or any limitations on my API. I’ve had to figure out a fast solution to limit the scale of this. The underneath solution is not a perfect one, as it’s not fixing the problem (unlike limiting unsuccessful login and captcha). This solution is only “slowing” down the brute-force process.

The idea is fairly simple: You can send max 5 requests per minute to an endpoint. The documentation for this can be found here

limit_req_zone $binary_remote_addr zone=login_zone:10m rate=5r/m;

So we create a 10 megabytezone for our request. We limit the number of requests to 5 requests per minute. It’s a login endpoint, so how many times would you like to login during 1 minute?

limit_req_status 429;

If you exceed the 5req is 1 minute you get a “Too many requests” status code.

You insert your limit inside the location block it’s meant to work with:

    location /login {
                proxy_cache_use_stale off;
                proxy_cache_lock off;
                client_max_body_size 20m;
                limit_req zone=login_zone burst=5 nodelay;

                proxy_pass http://api/login;
    }

Thanks,
Wizard

GPG key adding script for Debian*

*Debian based systems

There might be an easier way. Or maybe there is even an automatic way to do it. I couldn’t be bothered to search long enough.

Recently I’ve had to reinstall my system on a clean SSD drive. Some of the things were copies, but as Debian released it’s new stable (and testing, as I’m using this one) version I could install it from scratch. My pain was adding multiple keys so I’ve semi-automated it by creating a script.

The steps to reproduce are:

 apt install dirmngr gnupg 

 

The script:


#!/bin/bash

for var in "$@"
do
echo "Your key is:" $var
gpg --recv-keys $1
gpg --export $1 | apt-key add -
done

$@ passes all parameters to the script. The loop is using each element to increment itself using it as “var” variable. To use the script you need to:


chmod +x script.sh

and you use it like


./script.sh key1 ... keyN

voila’

Proxy for yum

Short post, short story. If your server is in a separated network without “internet” connectivity, but you have a proxy server set up in the network you can download the packages from official repos!

In /etc/yum.conf add

proxy=https://IP:PORT

and voila’

Serve error code via Haproxy.

Quest: Serve error code via Haproxy. For testing reasons etc.

1) Creaate a backend:

backend error
mode http
log global
option httplog
errorfile 500 /etc/haproxy/errorpages/503.http
errorfile 502 /etc/haproxy/errorpages/503.http
errorfile 503 /etc/haproxy/errorpages/503.http
errorfile 504 /etc/haproxy/errorpages/503.http

2) Create the errorpage:


HTTP/1.0 503 Service Unavailable
Cache-Control: no-cache
Connection: close
Content-Type: text/html



Title of your site


<div style="margin:0 auto;width:960px;">500</div>



3) Add the use backend

use_backend error if { hdr(Host) -i bob.com }

4) What’s worth considering is adding the “testing” mode for some IP (or a whole class). Add a new acl:

acl office_ips src 192.168.1.0/25

5) Change the use_backend to


use_backend error if { hdr(Host) -i bob.com www.bob.com } office_ips

^THIS will redirect every request coming from bob.com or http://www.bob.com, that comes from the IPs declared in office_ips to the backend “error” and show an error