Sunday, November 03, 2013

Client Certificate Authentication Issues with Apache and OS X Mavericks

Found some good tutorials online but took a few days of troubleshooting for me to figure out why they were not working.  Still don't understand SSL and cryptography as much as I would like to.  Posting this incase anyone else runs into similar issues.

The 3 tutorials I found via googling were:

  • Apache
    • http://www.impetus.us/~rjmooney/projects/misc/clientcertauth.html
    • http://linuxconfig.org/apache-web-server-ssl-authentication
  • Nginx
    • http://nategood.com/client-side-certificate-authentication-in-ngi
I will recap the commands here for additional info on how it works read either of those.

# Create the CA Key and Certificate for signing Client Certs 
openssl req -config ./openssl.cnf -newkey rsa:2048 -nodes -keyform PEM -keyout ca.key -x509 -days 3650 -extensions certauth -outform PEM -out ca.cer
# Create the Server Key, CSR, and Certificate 
openssl genrsa -out server.key 2048

openssl req -config ./openssl.cnf -new -key server.key -out server.req

# We're self signing our own server cert here. This is a no-no in production. 
openssl x509 -req -in server.req -CA ca.cer -CAkey ca.key -set_serial 100 -extfile openssl.cnf -extensions server -days 365 -outform PEM -out server.cer
rm server.req

 # Create the Client Key and CSR I made a client.cnf file for attributes to match the client
openssl genrsa -out client.key 2048
openssl req -config ./client.cnf -new -key client.key -out client.req

# Sign the client certificate with our CA cert. Unlike signing our own server cert, this is what we want to do. 
openssl x509 -req -in client.req -CA ca.cer -CAkey ca.key -set_serial 101 -extfile openssl.cnf -extensions client -days 365 -outform PEM -out client.cer
openssl pkcs12 -export -inkey client.key -in client.cer -out client.p12
rm client.key client.cer client.req
This is where I ran into problems with some of the tutorials. Testing with CURL to connect to NGINX worked based on the tutorial at nategood.com worked.

curl -v -s -k --key client.key --cert client.cert https://example.com

But connecting following the first apache tutorial did not and the second one needed some additional steps.

There seems to be 2 reasons why:
  • OS X Mavericks hacked up CURL to not work with client certificates - http://curl.haxx.se/mail/archive-2013-10/0036.html
  • CURL prefers certificates to be combined in PEM format with Data Bags included - http://honglus.blogspot.in/2012/03/fix-curl-client-certificate-error-curl.html

# Install CURL via Homebrew (assuems you have brew installed and up to date) openssl is not required but the OS X version is old 
brew install openssl curl

# Convert the certificate to pkcs12 and back to pem 
openssl pkcs12 -in client.p12 -out client.pem -clcerts

Here is the apache config
...
SSLCACertificateFile /var/www/conf/ssl.crt/ca.crt
...
    SSLRequireSSL 
    SSLVerifyClient require 
    SSLVerifyDepth 10 

... 
Now I can connect with (NOTE: do not use the built in curl)
/usr/local/Cellar/curl/7.33.0/bin/curl -v -s -k --key client.pem --cert client.pem https://example.com

Wednesday, October 23, 2013

OS X Maverick pkg_resources.DistributionNotFound: pip==1.1

Kept getting the following issue with PIP and easy_install
Traceback (most recent call last):
  File "/usr/local/bin/pip", line 5, in
    from pkg_resources import load_entry_point
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/pkg_resources.py", line 2603, in
    working_set.require(__requires__)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/pkg_resources.py", line 666, in require
    needed = self.resolve(parse_requirements(requirements))
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/pkg_resources.py", line 565, in resolve
    raise DistributionNotFound(req)  # XXX put more info here
pkg_resources.DistributionNotFound: pip==1.1
Ran the following to fix it:
wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
sudo python ez_setup.py
sudo easy_install -U pip

Tuesday, April 23, 2013

Django Admin Filter OR queries

Django admin in 1.4+ support the query parameter __in for filtering on multiple values of the same field.  Adding this to the admin took some work but is possible, I am not sure if this is the best way to do it but it does work.

Here is a snippet of my admin.py file
https://gist.github.com/justhamade/5447780

Sunday, April 07, 2013

Securing LAMP for Ubuntu 12.04 LTS

This is a summary of this post http://www.thefanclub.co.za/how-to/how-secure-ubuntu-1204-lts-server-part-1-basics

Setup non root user

ssh root@YOURSERVERIP
adduser YOUNONROOTUSER
useradd -G sudo YOUNONROOTUSER
logout
ssh YOURNONROOTUSER@YOURSERVERIP
sudo -i
Install LAMP, Security and other useful stuff
sudo apt-get install lamp-server^ ufw denyhosts fail2ban psad rkhunter chkrootkit nmap logwatch libdate-manip-perl apparmor apparmor-profiles tiger htop libxml2 libxml2-dev libxml2-utils libaprutil1 libaprutil1-dev libapache-mod-security -y
Setup UFW
sudo ufw enable
ufw status verbose
sudo ufw allow ssh
sudo ufw allow http
Secure shared mem (requires reboot)
echo 'tmpfs /dev/shm tmpfs defaults,noexec,nosuid 0 0' >> /etc/fstab
Disallow root ssh logins (can also change SSH PORT)
sed -i 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config
sed -i 's/Port 22/Port 2222/g' /etc/ssh/sshd_config
sudo /etc/init.d/ssh restart
Limit su command to users that have sudo
sudo dpkg-statoverride --update --add root sudo 4750 /bin/su
Harden network with sysctl settings.  This is what my /etc/sysctl.conf file ends up looking like with no comments
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.tcp_syncookies=1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
net.ipv4.icmp_echo_ignore_all = 1 
sudo sysctl -p
Prevent IP Spoofing
# The "order" line is only used by old versions of the C library.
order bing,hosts
nospoof on
multi on 
Secure PHP (assumes that exec, system, shell_exec, passthru are not already there)

sed -i 's/expose_php = On/expose_php = Off/g' /etc/php5/apache2/php.ini
sed '/^disable_functions/ s/$/,exec,system,shell_exec,passthru/' /etc/php5/apache2/php.ini > /etc/php5/apache2/php.ini
Secure Apache
sed -i 's/ServerTokens OS/ServerTokens Prod/g' /etc/apache2/conf.d/security
sed -i 's/ServerSignature On/ServerSignature Off/g' /etc/apache2/conf.d/security
echo 'Header unset ETag' >> /etc/apache2/conf.d/security
echo 'FileETag None' >> /etc/apache2/conf.d/security
a2enmod headers
/etc/init.d/apache2 restart
Update fail2ban
sed -s 'action = %(action_)s/action = %(action_mwl)s/g' s//etc/fail2ban/jail.conf
 


Monday, February 25, 2013

Vagrant on Cygwin

Not fully tested taken from memory and history so if anything is missing please comment.

Taken mostly from a good post here http://www.enrise.com/2012/12/git-and-vagrant-in-a-windows-environment/ Assumes you have latest cygwin and virtualbox installed.

Cygwin need svn and bash Install other deps
svn --force export http://apt-cyg.googlecode.com/svn/trunk/ /bin/
chmod +x /bin/apt-cyg
apt-cyg install make ruby curl git bsdtar ssh

Get Vagrant 1.1.0 dev from git (once this is stable then this step is not needed).
git clone https://github.com/mitchellh/vagrant.git
cd vagrant 

Update pull request for cygwin fix from here https://github.com/mitchellh/vagrant/pull/1366
curl https://github.com/mitchellh/vagrant/pull/1366.patch | git am

Install gem so deps are install then rake install to update to dev version with patches applied
gem install vagrant
rake install

Add VBOX_USER_HOME
export VBOX_USER_HOME=`pwd`/.VirtualBox/

Add symlink to VBoxManage
ln '/cygdrive/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe' /usr/local/bin/VBoxManage

Use vagrant
vagrant box add lucid32 http://files.vagrantup.com/lucid32.box
vagrant init lucid32
vagrant up

You May get an error when starting up. This is because the Virtual box guest additions need to be installed so the directory can be mounted
vagrant ssh
sudo apt-get install virtualbox-guest-addition

Tuesday, November 06, 2012

Stackato

wget http://downloads.activestate.com/stackato/vm/v2.4.3/stackato-vm-vbox-v2.4.3.zip
unzip stackato-vm-vbox-v2.4.3.zip
cd Stackato-VM
VBoxManage import Stackato-v2.4.3.ovf
VBoxManage modifyvm Stackato-v2.4.3 --nic1 bridged --bridgeadapter1 eth0
VBoxManage startvm Stackato-v2.4.3 --type headless
To figure out the ip
# scan port 22
nmap -p 22 --open -sV 192.168.X.0/24
VBoxManage showvminfo Stackato-v2.4.3 | grep MAC
# OUTPUT IS: NIC 1:           MAC: 080027656420, Attachment: Bridged Interface 'eth0', Cable connected: on, Trace: off (file: none), Type: 82540EM, Reported speed: 0 Mbps, Boot priority: 0, Promisc Policy: deny
arp -an | grep -i 08:00:27:65:64:20 
Install stackato client
wget http://downloads.activestate.com/stackato/client/v1.5/stackato-1.5-linux-glibc2.3-x86_64.zip
unzip stackato-1.5-linux-glibc2.3-x86_64.zip 
cd stackato-1.5-linux-glibc2.3-x86_64/
sudo mv stackato /usr/local/bin/.
stackato

Saturday, March 31, 2012

ISPConfig 3.0.4.3 with Django 1.4, Virtualenv and WSGI on Debian Squeeze

I recently go a killer deal on a VPS at http://chicagovps.net/ so I am moving all my stuff from my Webfaction and Linode to my own VPS. I want something to easily manage my apache configs, dns and mail still and have used ISPConfig in the past and found it pretty good for a free open source program. I actually like it better than cPanel or DirectAdmin which I find too restrictive.

Moving my Django projects from Webfaction will take a bit of work. ISPConfig has some nice options in the GUI for PHP but the Python option uses mod_python :(.

This will not be a complete guide but as usual some documentation for myself. It assumes that ISPConfig is already setup and working, there is an decent setup guide in docs/INSTALL_DEBIAN_6.0_courier_mydns.txt and some older but still useable docs here http://www.howtoforge.com/perfect-server-debian-lenny-ispconfig3.

First you need to install some additional packages
apt-get install python-setuptools libapache2-mod-wsgi python-dev -y
easy_install pip
pip install virtualenv

Then you need to setup your site in ISPConfig and copy your Django project to it or start a new one. For simplicity we will just create a new one here
cd /var/www/mysite.com/
virtualenv myproject-env
. /myproject-env/bin/activate
pip install mysql-python
pip install PIL
pip install django
django startproject myproject
This will create a wsgi.py file in myproject/myproject/wsgi.py

Then in your ISPConfig Site go to Sites > Website > mysite.com > Options and in the Apache Directive add the following. Make sure to change the path to the correct absolute path.
Alias /media/ /var/www/clients/client0/web1/myproject/myproject/media/
Alias /static/ /var/www/clients/client0/web1/myproject/myproject/static/

Alias /robots.txt /var/www/clients/client0/web1/myproject/myproject/static/robots.txt
Alias /favicon.ico /var/www/clients/client0/web1/myproject/myproject/static/images/favicon.ico
 

WSGIDaemonProcess mysite.com user=web1 group=client0 python-path=/var/www/clients/client0/web1:/var/www/clients/client0/web1/myproject-env/lib/python2.6/site-packages
WSGIProcessGroup mysite.com
WSGIScriptAlias / /var/www/clients/client0/web1/myproject/myproject/wsgi.py
<Directory /var/www/clients/client0/web1/myproject>
Order deny,allow
Allow from all
</Directory>
<Directory /var/www/clients/client0/web1/myproject>
Order deny,allow
Allow from all
</Directory>

<Directory /var/www/clients/client0/web1/myproject>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>
This assumes that STATIC_URL STATIC_ROOT MEDIA_URL and MEDIA_ROOT are set to /static/ and /media/ in myproject/myproject
# Django settings for myproject project.
import os

# Add this near the top
PROJECT_DIR = os.path.abspath(os.path. dirname(__file__))

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = PROJECT_DIR + '/media'

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = '/media/'

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = PROJECT_DIR + '/static'

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'

That should be it.  Make sure that user web1 and group client0 are the owners of the correct directories and files and have exec permission.