]> granicus.if.org Git - pgbouncer/commitdiff
tls: Test scripts
authorMarko Kreen <markokr@gmail.com>
Mon, 3 Aug 2015 18:56:43 +0000 (21:56 +0300)
committerMarko Kreen <markokr@gmail.com>
Mon, 3 Aug 2015 20:20:10 +0000 (23:20 +0300)
Todo: merge with main test.sh

test/ssl/lib.sh [new file with mode: 0644]
test/ssl/newca.sh [new file with mode: 0755]
test/ssl/newsite.sh [new file with mode: 0755]
test/ssl/test.ini [new file with mode: 0644]
test/ssl/test.sh [new file with mode: 0755]

diff --git a/test/ssl/lib.sh b/test/ssl/lib.sh
new file mode 100644 (file)
index 0000000..8e1716f
--- /dev/null
@@ -0,0 +1,52 @@
+#! /bin/sh
+
+# PEM format
+
+# req fields
+# C  = Country
+# ST = State/Province
+# L = Locality
+# O = Organization
+# OU = Org Unit
+# CN = commonName
+# ? = emailAddress
+
+umask 077
+
+run() {
+  echo '$' "$@"
+  "$@" 2>&1 | sed 's/^/  > /' 
+}
+
+# key -> csr
+run_req() {
+  tmp="csr.template"
+  args=""
+  while test "$1" != '--'; do
+    args="$args $1"
+    shift
+  done
+  shift
+
+  (
+    echo "[req]"
+    echo "prompt=no"
+    echo "distinguished_name=req_distinguished_name"
+    echo "[req_distinguished_name]"
+    for arg; do echo "$arg"; done
+  ) > "$tmp"
+  run openssl req $args -config "$tmp"
+  rm -f csr.template
+}
+
+run_ca() {
+  ser=`cat ${CaName}/serial`
+  run openssl ca -batch -config "${CaName}/config.ini" "$@"
+  while test "$1" != '-out'; do
+    shift
+  done
+  if test "$1" = '-out'; then
+    cp "${CaName}/certs/$ser.pem" "$2"
+  fi
+}
+
diff --git a/test/ssl/newca.sh b/test/ssl/newca.sh
new file mode 100755 (executable)
index 0000000..fecfc24
--- /dev/null
@@ -0,0 +1,70 @@
+#! /bin/sh
+
+# create new CA
+
+set -e
+
+test -n "$1" || {
+  echo "usage: $0 CaName [K=V]*"
+  exit 1
+}
+
+test -d "$1" && {
+  echo "CA '$1' already exists"
+  exit 1
+}
+
+name="$1"
+shift
+
+mkdir -p "$name"/certs
+mkdir -p "$name"/sites
+touch "$name"/index.txt
+echo 01 > "$name"/serial
+
+. ./lib.sh
+
+days=10240
+
+#run openssl genrsa -out "$name/ca.key" $ksize
+run openssl ecparam -name prime256v1 -genkey -out "$name/ca.key"
+
+# self-signed cert
+run_req -new -x509 -days $days -key "$name/ca.key" -out "$name/ca.crt" -- "$@"
+
+
+cat > "$name"/config.ini <<EOF
+[ca]
+default_ca = test-ca
+
+[test-ca]
+dir            = $name                # top dir
+database       = \$dir/index.txt      # index file.
+new_certs_dir  = \$dir/certs          # new certs dir
+certificate    = \$dir/ca.crt         # The CA cert
+serial         = \$dir/serial         # serial no file
+private_key    = \$dir/ca.key         # CA private key
+
+default_md = sha256
+
+policy = pol-user
+
+[pol-user]
+C = supplied
+L = supplied
+#ST = supplied
+O = supplied
+OU = supplied
+CN = supplied
+emailAddress = supplied
+
+[pol-server]
+C = supplied
+L = supplied
+#ST = supplied
+O = supplied
+OU = supplied
+CN = supplied
+
+EOF
+
diff --git a/test/ssl/newsite.sh b/test/ssl/newsite.sh
new file mode 100755 (executable)
index 0000000..cd0b2b9
--- /dev/null
@@ -0,0 +1,34 @@
+#! /bin/sh
+
+# new server key + cert under some CA
+
+test -n "$2" || {
+  echo "usage: $0 <CaName> <SiteDns>"
+  exit 1
+}
+
+test -f "$1/ca.key" || {
+  echo "CA $1 does not exist"
+  exit 1
+}
+
+days=10240
+
+. ./lib.sh
+
+CaName="$1"
+DstName="$2"
+shift 2
+
+ser=`cat $CaName/serial`
+
+pfx=$CaName/sites/${ser}-$DstName
+
+run openssl ecparam -genkey -name prime256v1 -out $pfx.key
+
+# cert reqs
+run_req -new -key "$pfx.key" -out "$pfx.csr" -- CN="$DstName" "$@"
+
+# accept certs
+run_ca -days $days -policy pol-server -in "$pfx.csr" -out "$pfx.crt"
+
diff --git a/test/ssl/test.ini b/test/ssl/test.ini
new file mode 100644 (file)
index 0000000..9b75b40
--- /dev/null
@@ -0,0 +1,93 @@
+;; database name = connect string
+[databases]
+
+p0 = port=6666 host=localhost dbname=p0 user=bouncer pool_size=2
+p1 = port=6666 host=localhost dbname=p1 user=bouncer
+p2 = port=6668 host=localhost dbname=p2 user=bouncer
+
+;; Configuation section
+[pgbouncer]
+
+;;;
+;;; Administrative settings
+;;;
+
+logfile = tmp/test.log
+pidfile = tmp/test.pid
+
+;;;
+;;; Where to wait for clients
+;;;
+
+; ip address or * which means all ip-s
+listen_addr = 127.0.0.1
+listen_port = 6667
+unix_socket_dir = /tmp
+
+;;;
+;;; Authentication settings
+;;;
+
+; any, trust, plain, crypt, md5
+;auth_type = trust
+auth_file = tmp/userlist.txt
+
+;;;
+;;; Pooler personality questions
+;;;
+
+; When server connection is released back to pool:
+;   session      - after client disconnects
+;   transaction  - after transaction finishes
+;   statement    - after statement finishes
+pool_mode = statement
+
+; When taking idle server into use, this query is ran first.
+;
+; Query for session pooling:
+;   ABORT; RESET ALL; SET SESSION AUTHORIZATION DEFAULT
+; Query for statement/transaction pooling:
+;   SELECT 1
+; Empty query disables the functionality
+server_check_query = select 1
+
+; If server was used more recently that this many seconds ago,
+; skip the check query.  If 0, the check query is always ran.
+server_check_delay = 10
+
+;;;
+;;; Connection limits
+;;;
+
+; total number of clients that can connect
+max_client_conn = 10
+default_pool_size = 5
+
+;;;
+;;; Timeouts
+;;;
+
+; Close server connection if its been connected longer.
+server_lifetime = 120
+
+; Close server connection if its not been used in this time.
+; Allows to clean unneccessary connections from pool after peak.
+server_idle_timeout = 60
+
+; Cancel connection attepmt if server does not answer takes longer.
+server_connect_timeout = 15
+
+; If server login failed (server_connect_timeout or auth failure)
+; then wait this many second.
+server_login_retry = 15
+
+; Dangerous.  Server connection is closed if query does not return
+; in this time.  Should be used to survive network problems,
+; _not_ as statement_timeout. (default: 0)
+query_timeout = 0
+
+; Dangerous.  Client connection is closed if no activity in this time.
+; Should be used to survive network problems. (default: 0)
+client_idle_timeout = 0
+
+
diff --git a/test/ssl/test.sh b/test/ssl/test.sh
new file mode 100755 (executable)
index 0000000..5c50eba
--- /dev/null
@@ -0,0 +1,248 @@
+#! /bin/sh
+
+rm -rf TestCA1
+
+(
+./newca.sh TestCA1 C=QQ O=Org1 CN="TestCA1"
+./newsite.sh TestCA1 localhost C=QQ O=Org1 L=computer OU=db
+./newsite.sh TestCA1 bouncer C=QQ O=Org1 L=computer OU=Dev
+./newsite.sh TestCA1 random C=QQ O=Org1 L=computer OU=Dev
+) > /dev/null
+
+export PATH=/usr/lib/postgresql/9.4/bin:$PATH
+export PGDATA=$PWD/pgdata
+export PGHOST=localhost
+export PGPORT=6667
+export EF_ALLOW_MALLOC_0=1
+
+mkdir -p tmp
+
+BOUNCER_LOG=tmp/test.log
+BOUNCER_INI=test.ini
+BOUNCER_PID=tmp/test.pid
+BOUNCER_PORT=`sed -n '/^listen_port/s/listen_port.*=[^0-9]*//p' $BOUNCER_INI`
+BOUNCER_EXE="../../pgbouncer"
+
+LOGDIR=tmp
+NC_PORT=6668
+PG_PORT=6666
+PG_LOG=$LOGDIR/pg.log
+
+pgctl() {
+       pg_ctl -o "-p $PG_PORT" -D $PGDATA $@ >>$PG_LOG 2>&1
+}
+
+rm -f core
+ulimit -c unlimited
+
+for f in pgdata/postmaster.pid tmp/test.pid; do
+       test -f $f && { kill `cat $f` || true; }
+done
+
+mkdir -p $LOGDIR
+rm -fr $BOUNCER_LOG $PG_LOG
+rm -rr $PGDATA
+
+if [ ! -d $PGDATA ]; then
+       echo "initdb"
+       mkdir $PGDATA
+       initdb --nosync >> $PG_LOG 2>&1
+       sed -r -i "/unix_socket_director/s:.*(unix_socket_director.*=).*:\\1 '/tmp':" pgdata/postgresql.conf
+       echo "port = $PG_PORT" >> pgdata/postgresql.conf
+       echo "log_connections = on" >> pgdata/postgresql.conf
+       echo "log_disconnections = on" >> pgdata/postgresql.conf
+       cp pgdata/postgresql.conf pgdata/postgresql.conf.orig
+       cp pgdata/pg_hba.conf pgdata/pg_hba.conf.orig
+       cp pgdata/pg_ident.conf pgdata/pg_ident.conf.orig
+
+       cp -p TestCA1/sites/01-localhost.crt pgdata/server.crt
+       cp -p TestCA1/sites/01-localhost.key pgdata/server.key
+       cp -p TestCA1/ca.crt pgdata/root.crt
+
+       echo '"bouncer" "zzz"' > tmp/userlist.txt
+
+       chmod 600 pgdata/server.key
+       chmod 600 tmp/userlist.txt
+fi
+
+pgctl start
+sleep 5
+
+echo "createdb"
+psql -p $PG_PORT -l | grep p0 > /dev/null || {
+       psql -p $PG_PORT -c "create user bouncer" template1
+       createdb -p $PG_PORT p0
+       createdb -p $PG_PORT p1
+}
+
+$BOUNCER_EXE -d $BOUNCER_INI
+sleep 1
+
+reconf_bouncer() {
+       cp test.ini tmp/test.ini
+       for ln in "$@"; do
+               echo "$ln" >> tmp/test.ini
+       done
+       test -f tmp/test.pid && kill `cat tmp/test.pid`
+       sleep 1
+       $BOUNCER_EXE -v -v -v -d tmp/test.ini
+}
+
+reconf_pgsql() {
+       cp pgdata/postgresql.conf.orig pgdata/postgresql.conf
+       for ln in "$@"; do
+               echo "$ln" >> pgdata/postgresql.conf
+       done
+       pgctl stop
+       pgctl start
+       sleep 1
+}
+
+
+#
+#  fw hacks
+#
+
+#
+# util functions
+#
+
+complete() {
+       test -f $BOUNCER_PID && kill `cat $BOUNCER_PID` >/dev/null 2>&1
+       pgctl -m fast stop
+       rm -f $BOUNCER_PID
+}
+
+die() {
+       echo $@
+       complete
+       exit 1
+}
+
+admin() {
+       psql -h /tmp -U pgbouncer pgbouncer -c "$@;" || die "Cannot contact bouncer!"
+}
+
+runtest() {
+       echo -n "`date` running $1 ... "
+       eval $1 >$LOGDIR/$1.log 2>&1
+       if [ $? -eq 0 ]; then
+               echo "ok"
+       else
+               echo "FAILED"
+       fi
+       date >> $LOGDIR/$1.log
+
+       # allow background processing to complete
+       wait
+       # start with fresh config
+       kill -HUP `cat $BOUNCER_PID`
+}
+
+psql_pg() {
+       psql -U bouncer -h 127.0.0.1 -p $PG_PORT "$@"
+}
+
+psql_bouncer() {
+       PGUSER=bouncer psql "$@"
+}
+
+# server_lifetime
+test_server_ssl() {
+       reconf_bouncer "auth_type = trust" "server_tls_sslmode = require" 
+       echo "hostssl all all 127.0.0.1/32 trust" > pgdata/pg_hba.conf
+       reconf_pgsql "ssl=on" "ssl_ca_file='root.crt'"
+       psql_bouncer -q -d p0 -c "select 'ssl-connect'" | tee tmp/test.tmp0
+       grep -q "ssl-connect"  tmp/test.tmp0
+       rc=$?
+       return $rc
+}
+
+test_server_ssl_verify() {
+       reconf_bouncer "auth_type = trust" \
+               "server_tls_sslmode = verify-full" \
+               "server_tls_ca_file = TestCA1/ca.crt"
+
+       echo "hostssl all all 127.0.0.1/32 trust" > pgdata/pg_hba.conf
+       reconf_pgsql "ssl=on" "ssl_ca_file='root.crt'" 
+       psql_bouncer -q -d p0 -c "select 'ssl-full-connect'" | tee tmp/test.tmp1
+       grep -q "ssl-full-connect"  tmp/test.tmp1
+       rc=$?
+       return $rc
+}
+
+test_server_ssl_pg_auth() {
+       reconf_bouncer "auth_type = trust" \
+               "server_tls_sslmode = verify-full" \
+               "server_tls_ca_file = TestCA1/ca.crt" \
+               "server_tls_key_file = TestCA1/sites/02-bouncer.key" \
+               "server_tls_cert_file = TestCA1/sites/02-bouncer.crt"
+
+       echo "hostssl all all 127.0.0.1/32 cert" > pgdata/pg_hba.conf
+       reconf_pgsql "ssl=on" "ssl_ca_file='root.crt'"
+       psql_bouncer -q -d p0 -c "select 'ssl-cert-connect'" | tee tmp/test.tmp2
+       grep "ssl-cert-connect"  tmp/test.tmp2
+       rc=$?
+       return $rc
+}
+
+test_client_ssl() {
+       reconf_bouncer "auth_type = trust" "server_tls_sslmode = prefer" \
+               "client_tls_sslmode = require" \
+               "client_tls_key_file = TestCA1/sites/01-localhost.key" \
+               "client_tls_cert_file = TestCA1/sites/01-localhost.crt"
+       echo "host all all 127.0.0.1/32 trust" > pgdata/pg_hba.conf
+       reconf_pgsql "ssl=on" "ssl_ca_file='root.crt'"
+       psql_bouncer -q -d "dbname=p0 sslmode=require" -c "select 'client-ssl-connect'" | tee tmp/test.tmp
+       grep -q "client-ssl-connect"  tmp/test.tmp
+       rc=$?
+       return $rc
+}
+
+test_client_ssl() {
+       reconf_bouncer "auth_type = trust" "server_tls_sslmode = prefer" \
+               "client_tls_sslmode = require" \
+               "client_tls_key_file = TestCA1/sites/01-localhost.key" \
+               "client_tls_cert_file = TestCA1/sites/01-localhost.crt"
+       echo "host all all 127.0.0.1/32 trust" > pgdata/pg_hba.conf
+       reconf_pgsql "ssl=on" "ssl_ca_file='root.crt'"
+       psql_bouncer -q -d "dbname=p0 sslmode=verify-full sslrootcert=TestCA1/ca.crt" -c "select 'client-ssl-connect'" | tee tmp/test.tmp 2>&1
+       grep -q "client-ssl-connect"  tmp/test.tmp
+       rc=$?
+       return $rc
+}
+
+test_client_ssl_auth() {
+       reconf_bouncer "auth_type = cert" "server_tls_sslmode = prefer" \
+               "client_tls_sslmode = verify-full" \
+               "client_tls_ca_file = TestCA1/ca.crt" \
+               "client_tls_key_file = TestCA1/sites/01-localhost.key" \
+               "client_tls_cert_file = TestCA1/sites/01-localhost.crt"
+       echo "host all all 127.0.0.1/32 trust" > pgdata/pg_hba.conf
+       reconf_pgsql "ssl=on" "ssl_ca_file='root.crt'"
+       psql_bouncer -q -d "dbname=p0 sslmode=require sslkey=TestCA1/sites/02-bouncer.key sslcert=TestCA1/sites/02-bouncer.crt" \
+               -c "select 'client-ssl-connect'" | tee tmp/test.tmp 2>&1
+       grep -q "client-ssl-connect"  tmp/test.tmp
+       rc=$?
+       return $rc
+}
+
+testlist="
+test_server_ssl
+test_server_ssl_verify
+test_server_ssl_pg_auth
+test_client_ssl
+test_client_ssl_auth
+"
+if [ $# -gt 0 ]; then
+       testlist="$*"
+fi
+
+for test in $testlist
+do
+       runtest $test
+done
+
+complete
+
+# vim: sts=0 sw=8 noet nosmarttab: