These are my links for June 30th through July 2nd:
Tag: integration
SVN Server Integration with HTTPS, Active Directory, PAM & Winbind
In this post I’d like to explain how it’s possible to integrate SVN (Subversion) source control using WebDAV and HTTPS using Apache and Active Directory to provide authentication and access control.
It’s generally accepted that SVN over WebDAV/HTTPS Â provides finer granulation security controls than SVN+SSH. The problem is that SVN+SSH is really easy to set up, requiring knowledge of svnadmin and the filesystem and very little else but WebDAV+HTTPS requires knowledge of Apache and its modules relating to WebDAV, authentication and authorisation which is quite a lot more to ask. Add to that authenticating to AD and you have yourself a lovely string of delicate single point of failure components. Ho-hum, not a huge amount you can do about that but at least the Apache components are pretty robust.
For this article I’m using CentOS but everything should be transferrable to any distribution with a little tweakage.
Repository Creation
Firstly then, pick a disk or volume with plenty of space, we’re using make your repository – same as you would for svn+ssh:
svnadmin create /var/svn/repos
Apache Modules
Install the prerequisite Apache modules:
yum install mod_dav_svn
This should also install mod_authz_svn which we’ll also be making use of. Both should end up in Apache’s module directory, in this case /etc/httpd/modules/
Download and install mod_authnz_external from its Google Code page. This allows Apache basic authentication to hook into an external authentication mechanism. mod_authnz_external.so should end up in Apache’s module directory but in my case it ended up in its default location of /usr/lib/httpd/modules/
.
Download and install the companion pwauth utility from its Google Code page. In my case it installs to /usr/local/sbin/pwauth and needs suexec permissions (granted using chmod +s
).
Apache Configuration (HTTP)
ServerName svn.example.com
ServerAdmin me@example.com
Listen *:80
NameVirtualHost *:80
User nobody
Group nobody
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_svn_module modules/mod_authz_svn.so
LoadModule authnz_external_module modules/mod_authnz_external.so
LogFormat "%v %A:%p %h %l %u %{%Y-%m-%d %H:%M:%S}t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" clean
CustomLog /var/log/httpd/access_log clean
<virtualhost *:80>
ServerName svn.example.com
AddExternalAuth pwauth /usr/local/sbin/pwauth
SetExternalAuthMethod pwauth pipe
<location / >
DAV svn
SVNPath /var/svn/repos
AuthType Basic
AuthName "SVN Repository"
AuthzSVNAccessFile /etc/httpd/conf/authz_svn.acl
AuthBasicProvider external
AuthExternal pwauth
Satisfy Any
<limitexcept GET PROPFIND OPTIONS REPORT>
Require valid-user
</limitexcept>
</location>
</virtualhost>
Network Time (NTP)
In order to join a Windows domain, accurate and synchronised time is crucial, so you’ll need to be running NTPd.
yum install ntp
chkconfig ntpd on
ntpdate ntp.ubuntu.com
service ntpd start
Samba Configuration
Here’s where AD comes in and in my experience this is by far the most unreliable service. Install and configure samba:
yum install samba
chkconfig winbind on
Edit your /etc/samba/smb.conf
to pull information from AD.
[global]
workgroup = EXAMPLE
realm = EXAMPLE.COM
security = ADS
allow trusted domains = No
use kerberos keytab = Yes
log level = 3
log file = /var/log/samba/%m
max log size = 50
printcap name = cups
idmap backend = idmap_rid:EXAMPLE=600-20000
idmap uid = 600-20000
idmap gid = 600-20000
template shell = /bin/bash
winbind enum users = Yes
winbind enum groups = Yes
winbind use default domain = Yes
winbind offline logon = yes
Join the machine to the domain – you’ll need an account with domain admin credentials to do this:
net ads join -U administrator
Check the join is behaving ok:
[root@svn conf]# net ads info
LDAP server: 192.168.100.10
LDAP server name: ad00.example.com
Realm: EXAMPLE.COM
Bind Path: dc=EXAMPLE,dc=COM
LDAP port: 389
Server time: Tue, 15 May 2012 22:44:34 BST
KDC server: 192.168.100.10
Server time offset: 130
(Re)start winbind to pick up the new configuration:
service winbind restart
PAM & nsswitch.conf
PAM needs to know where to pull its information from, so we tell it about the new winbind service in /etc/pam.d/system-auth
.
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth required pam_env.so
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth sufficient pam_winbind.so try_first_pass
auth required pam_deny.so
account required pam_unix.so broken_shadow
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 500 quiet
account [default=bad success=ok user_unknown=ignore] pam_winbind.so
account required pam_permit.so
password requisite pam_cracklib.so try_first_pass retry=3
password sufficient pam_unix.so md5 shadow nullok try_first_pass use_authtok
password sufficient pam_winbind.so use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required /lib/security/pam_mkhomedir.so
session required pam_unix.so
session optional pam_winbind.so
YMMV with PAM. It can take quite a lot of fiddling around to make it work perfectly. This obviously has an extremely close correlation to how flaky users find the authentication service. If you’re running on 64-bit you may find you need to install 64-bit versions of pam modules, e.g. mkhomedir which aren’t installed by default.
We also modify nsswitch.conf
to tell other, non-pam aspects of the system where to pull information from:
passwd: files winbind
shadow: files winbind
group: files winbind
To check the authentication information is coming back correctly you can use wbinfo
but I like seeing data by using getent group
or getent passwd
. The output of these two commands will contain domain accounts if things are working correctly and only local system accounts otherwise.
External Authentication
We’re actually going to use system accounts for authentication. To stop people continuing to use svn+ssh (and thus bypassing the authorisation controls) we edit /etc/ssh/sshd_config
and use AllowUsers
or AllowGroups
and specify all permitted users. Using AllowGroups will also provide AD group control of permitted logins but as the list is small it’s probably overkill. My sshd_config list looks a lot like this:
AllowUsers root rmp contractor itadmin
To test external authentication run /usr/local/sbin/pwauth
as below. “yay” should be displayed if things are working ok. Note the password here is displayed in clear-text:
[root@svn conf]# pwauth && echo 'yay' || echo 'nay'
rmp
mypassword
Access Controls
/etc/httpd/authz_svn.conf
is the only part which should require any modifications over time – the access controls specify who is allowed to read and/or write to each svn project, in fact as everything’s a URL now you can arbitrarily restrict subfolders of projects too but that’s a little OTT. It can be arbitrarily extended and can take local and active directory usernames. I’m sure mod_authz_svn has full documentation about what you can and can’t put in here.
#
# Allow anonymous read access to everything by default.
#
[/]
* = r
rmp = rw
[/myproject]
rmp = rw
bob = rw
...
SSL
So far that’s all the basic components. The last piece in the puzzle is enabling SSL for Apache. I use the following /etc/httpd/httpd.conf
:
ServerName svn.example.com
ServerAdmin me@example.com
Listen *:80
NameVirtualHost *:80
User nobody
Group nobody
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_svn_module modules/mod_authz_svn.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule authnz_external_module modules/mod_authnz_external.so
Include conf.d/ssl.conf
LogFormat "%v %A:%p %h %l %u %{%Y-%m-%d %H:%M:%S}t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" clean
CustomLog /var/log/httpd/access_log clean
<virtualhost *:80>
ServerName svn.example.com
Rewrite / https://svn.example.com/ [R=permanent,L]
</virtualhost>
<virtualhost *:443>
ServerName svn.example.com
AddExternalAuth pwauth /usr/local/sbin/pwauth
SetExternalAuthMethod pwauth pipe
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
SSLCertificateFile /etc/httpd/conf/svn.crt
SSLCertificateKeyFile /etc/httpd/conf/svn.key
<location />
DAV svn
SVNPath /var/svn/repos
AuthType Basic
AuthName "SVN Repository"
AuthzSVNAccessFile /etc/httpd/conf/authz_svn.acl
AuthBasicProvider external
AuthExternal pwauth
Satisfy Any
<limitexcept GET PROPFIND OPTIONS REPORT>
Require valid-user
</limitexcept>
</virtualhost>
/etc/httpd/conf.d/ssl.conf
is pretty much the unmodified distribution ssl.conf and looks like this:
LoadModule ssl_module modules/mod_ssl.so
Listen 443
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
SSLPassPhraseDialog builtin
SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout 300
SSLMutex default
SSLRandomSeed startup file:/dev/urandom 256
SSLRandomSeed connect builtin
SSLCryptoDevice builtin
SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
You’ll need to build yourself a certificate, self-signed if necessary, but that’s a whole other post. I recommend searching the web for “openssl self signed certificate” and you should find what you need. The above httpd.conf references the key and certificate under /etc/httpd/conf/svn.key
and /etc/httpd/conf/svn.crt
respectively.
The mod_authnz_external+pwauth combination can be avoided if you can persuade mod_authz_ldap to play nicely. There are a few different ldap modules around on the intertubes and after a lot of trial and even more error I couldn’t make any of them work reliably if at all.
And if all this leaves you feeling pretty nauseous it’s quite natural. To remedy this, go use git
instead.
Bookmarks for April 30th through May 11th
These are my links for April 30th through May 11th:
- Meganet’s Dominator I snoops on four GSM convos at once, fits in your overnight bag — Engadget –
- SFBags – WaterField Designs – Muzetto Bags – Laptop Bag –
- LESS – Leaner CSS – looks just like Sass
- thiblahute/Gsoc2009 – GNOME Live! – synchronised google docs as a network drive
- GMDesk – run Gmail, Google Calendar, Google Docs and Google Maps as a stand-alone installable application –
Active Directory + Linux account integration
Firstly a note of warning. I’ve done this mostly using CentOS but there’s no reason it shouldn’t work just as well on other distributions. I’ve gleaned a lot of this information by scouring a lot of other resources around the internet, FAQs, newsgroups etc. but as far as I can remember I wasn’t able to find a coherent article which described all of the required pieces of the puzzle.
Secondly the objective of this article is to have unified accounting across Windows & Linux, or at least as close as possible. We’re going to use Microsoft Active Directory, Kerberos, Samba, Winbind, pam and nsswitch. We’re also going to end up with consistent uids and gids across multiple linux clients.
/etc/samba/smb.conf
[global]
workgroup = PSYPHI
realm = PSYPHI.LOCAL
security = ADS
allow trusted domains = No
use kerberos keytab = Yes
log level = 3
log file = /var/log/samba/%m
max log size = 50
printcap name = cups
idmap backend = idmap_rid:PSYPHI=600-20000
idmap uid = 600-20000
idmap gid = 600-20000
template shell = /bin/bash
winbind enum users = Yes
winbind enum groups = Yes
winbind use default domain = Yes
/etc/krb5.conf
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
default_realm = PSYPHI.LOCAL
dns_lookup_realm = true
dns_lookup_kdc = true
ticket_lifetime = 24h
forwardable = yes
[realms]
EXAMPLE.COM = {
kdc = kerberos.example.com:88
admin_server = kerberos.example.com:749
default_domain = example.com
}
PSYPHI.LOCAL = {
}
[domain_realm]
.example.com = EXAMPLE.COM
example.com = EXAMPLE.COM
psyphi.local = PSYPHI.LOCAL
.psyphi.local = PSYPHI.LOCAL
[appdefaults]
pam = {
debug = false
ticket_lifetime = 36000
renew_lifetime = 36000
forwardable = true
krb4_convert = false
}
Next we join the machine to the AD domain – it’s necessary to specify a user with the right privileges. It also prompts for a password.
net ads join -U administrator
We can check things are working so far by trying to create a kerberos ticket using an existing username. Again it prompts us for a password.
kinit (username)
Then klist
gives us output something like this:
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: username@PSYPHI.LOCAL
Valid starting Expires Service principal
04/28/10 10:57:32 04/28/10 20:57:34 krbtgt/PSYPHI.LOCAL@PSYPHI.LOCAL
renew until 04/29/10 10:57:32
Kerberos 4 ticket cache: /tmp/tkt0
klist: You have no tickets cached
Cool, so we have a machine joined to the domain and able to use kerberos tickets. Now we can tell our system to use winbind for fetching account information:
/etc/pam.d/system-auth-ac
auth required pam_env.so
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth sufficient pam_krb5.so use_first_pass
auth required pam_deny.so
account required pam_unix.so broken_shadow
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 500 quiet
account [default=bad success=ok user_unknown=ignore] pam_krb5.so
account required pam_permit.so
password requisite pam_cracklib.so try_first_pass retry=3
password sufficient pam_unix.so md5 shadow nullok try_first_pass use_authtok
password sufficient pam_krb5.so use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required /lib/security/pam_mkhomedir.so
session required pam_unix.so
session optional pam_krb5.so
If we’re on a 64-bit distribution we’ll find that references to /lib need to be switched for /lib64, e.g. /lib64/security/pam_mkhomedir.so . This file will also create new home directories for users if they’re not present during first log-in.
/etc/nsswitch.conf
passwd: files winbind
shadow: files winbind
group: files winbind
hosts: files dns
bootparams: nisplus [NOTFOUND=return] files
ethers: files
netmasks: files
networks: files
protocols: files
rpc: files
services: files
netgroup: nisplus
publickey: nisplus
automount: files nisplus
aliases: files nisplus
Now we need to tell a few services to start on boot
chkconfig smb on
chkconfig winbind on
and start a few services now
service smb start
service winbind start
The Winbind+pam configuration can sometimes take a few minutes to settle down – I occasionally find it’s necessary to wait 5 or 10 minutes before accounts are available. YMMV.
getent passwd
Should now list local accounts (which take precedence) followed by domain accounts. Using ssh to the box as a domain user should make new home directories in /home/PSYPHI/username. If you decide to migrate home directories from /home make sure you change uid and gid to the new domain values for that user, then remove the old local account.
There are a handful of limitations of this approach –
- Though usernames and groupnames map ok, linux uids still don’t map to the windows uids so permissions don’t quite work across smb/cifs mounts
- The standard linux tools for user & group modification don’t work for domain accounts (adduser/usermod/groupadd/… etc.)
- Winbind seems unstable. On a lot of systems I’ve resorted to cronning a
service winbind restart
every 15 minutes, which seriously sucks - … and probably others too
For debugging /var/log/secure
is very useful, as are the samba logs in /var/log/samba/
.
Bookmarks for April 22nd through April 24th
These are my links for April 22nd through April 24th: