summaryrefslogtreecommitdiffstats
path: root/nova/cloudpipe
diff options
context:
space:
mode:
authorTodd Willey <todd@rubidine.com>2010-07-15 00:48:44 -0400
committerTodd Willey <todd@rubidine.com>2010-07-15 00:48:44 -0400
commit31b546231174237be027147cb9807034b52fcedc (patch)
treea4774580cd0eebd1e31079a6f0195719a54a3001 /nova/cloudpipe
parentc7f28358ad01e069ac60e4ee85c450c35c628dde (diff)
parent4253dd01389358a945ceb30c37a93865366c1783 (diff)
Merge branch 'master' into rackspace_api
Diffstat (limited to 'nova/cloudpipe')
-rw-r--r--nova/cloudpipe/__init__.py31
-rw-r--r--nova/cloudpipe/api.py61
-rwxr-xr-xnova/cloudpipe/bootscript.sh65
-rw-r--r--nova/cloudpipe/client.ovpn.template47
-rw-r--r--nova/cloudpipe/pipelib.py102
5 files changed, 306 insertions, 0 deletions
diff --git a/nova/cloudpipe/__init__.py b/nova/cloudpipe/__init__.py
new file mode 100644
index 000000000..57ef14651
--- /dev/null
+++ b/nova/cloudpipe/__init__.py
@@ -0,0 +1,31 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2010 Anso Labs, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+:mod:`nova.cloudpipe` -- VPN Server Management
+=====================================================
+
+.. automodule:: nova.cloudpipe
+ :platform: Unix
+ :synopsis: An OpenVPN server for every nova user.
+.. moduleauthor:: Devin Carlen <devin.carlen@gmail.com>
+.. moduleauthor:: Vishvananda Ishaya <vishvananda@yahoo.com>
+.. moduleauthor:: Joshua McKenty <jmckenty@gmail.com>
+"""
diff --git a/nova/cloudpipe/api.py b/nova/cloudpipe/api.py
new file mode 100644
index 000000000..610239c2e
--- /dev/null
+++ b/nova/cloudpipe/api.py
@@ -0,0 +1,61 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2010 Anso Labs, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Tornado REST API Request Handlers for CloudPipe
+"""
+
+import logging
+import urllib
+
+from nova import vendor
+import tornado.web
+
+from nova import crypto
+from nova.auth import users
+
+_log = logging.getLogger("api")
+_log.setLevel(logging.DEBUG)
+
+
+class CloudPipeRequestHandler(tornado.web.RequestHandler):
+ def get(self, path):
+ path = self.request.path
+ _log.debug( "Cloudpipe path is %s" % path)
+ if path.endswith("/getca/"):
+ self.send_root_ca()
+ self.finish()
+
+ def get_project_id_from_ip(self, ip):
+ cc = self.application.controllers['Cloud']
+ instance = cc.get_instance_by_ip(ip)
+ instance['project_id']
+
+ def send_root_ca(self):
+ _log.debug( "Getting root ca")
+ project_id = self.get_project_id_from_ip(self.request.remote_ip)
+ self.set_header("Content-Type", "text/plain")
+ self.write(crypto.fetch_ca(project_id))
+
+ def post(self, *args, **kwargs):
+ project_id = self.get_project_id_from_ip(self.request.remote_ip)
+ cert = self.get_argument('cert', '')
+ self.write(crypto.sign_csr(urllib.unquote(cert), project_id))
+ self.finish()
diff --git a/nova/cloudpipe/bootscript.sh b/nova/cloudpipe/bootscript.sh
new file mode 100755
index 000000000..639aad66f
--- /dev/null
+++ b/nova/cloudpipe/bootscript.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2010 Anso Labs, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# This gets zipped and run on the cloudpipe-managed OpenVPN server
+
+export SUPERVISOR="http://10.255.255.1:8773/cloudpipe"
+export VPN_IP=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{print $1}'`
+export BROADCAST=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f3 | awk '{print $1}'`
+export DHCP_MASK=`ifconfig | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f4 | awk '{print $1}'`
+export GATEWAY=`netstat -r | grep default | cut -d' ' -f10`
+export SUBJ=/C=US/ST=California/L=Mountain View/O=Anso Labs/OU=Nova Dev/CN=customer-vpn-$VPN_IP
+
+DHCP_LOWER=`echo $BROADCAST | awk -F. '{print $1"."$2"."$3"." $4 - 10 }'`
+DHCP_UPPER=`echo $BROADCAST | awk -F. '{print $1"."$2"."$3"." $4 - 1 }'`
+
+# generate a server DH
+openssl dhparam -out /etc/openvpn/dh1024.pem 1024
+
+# generate a server priv key
+openssl genrsa -out /etc/openvpn/server.key 2048
+
+# generate a server CSR
+openssl req -new -key /etc/openvpn/server.key -out /etc/openvpn/server.csr -batch -subj "$SUBJ"
+
+# URLEncode the CSR
+CSRTEXT=`cat /etc/openvpn/server.csr`
+CSRTEXT=$(python -c "import urllib; print urllib.quote('''$CSRTEXT''')")
+
+# SIGN the csr and save as server.crt
+# CURL fetch to the supervisor, POSTing the CSR text, saving the result as the CRT file
+curl $SUPERVISOR -d "cert=$CSRTEXT" > /etc/openvpn/server.crt
+curl $SUPERVISOR/getca/ > /etc/openvpn/ca.crt
+
+# Customize the server.conf.template
+cd /etc/openvpn
+
+sed -e s/VPN_IP/$VPN_IP/g server.conf.template > server.conf
+sed -i -e s/DHCP_SUBNET/$DHCP_MASK/g server.conf
+sed -i -e s/DHCP_LOWER/$DHCP_LOWER/g server.conf
+sed -i -e s/DHCP_UPPER/$DHCP_UPPER/g server.conf
+sed -i -e s/max-clients\ 1/max-clients\ 10/g server.conf
+
+echo "\npush \"route 10.255.255.1 255.255.255.255 $GATEWAY\"\n" >> server.conf
+echo "\npush \"route 10.255.255.253 255.255.255.255 $GATEWAY\"\n" >> server.conf
+echo "\nduplicate-cn\n" >> server.conf
+
+/etc/init.d/openvpn start
diff --git a/nova/cloudpipe/client.ovpn.template b/nova/cloudpipe/client.ovpn.template
new file mode 100644
index 000000000..a8ec5dc6e
--- /dev/null
+++ b/nova/cloudpipe/client.ovpn.template
@@ -0,0 +1,47 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2010 Anso Labs, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# NOVA user connection
+# Edit the following lines to point to your cert files:
+cert $certfile
+key $keyfile
+
+ca cacert.pem
+
+client
+dev tap
+proto udp
+
+remote $ip $port
+resolv-retry infinite
+nobind
+
+# Downgrade privileges after initialization (non-Windows only)
+user nobody
+group nogroup
+comp-lzo
+
+# Set log file verbosity.
+verb 2
+
+keepalive 10 120
+ping-timer-rem
+persist-tun
+persist-key
diff --git a/nova/cloudpipe/pipelib.py b/nova/cloudpipe/pipelib.py
new file mode 100644
index 000000000..5f6ccf82e
--- /dev/null
+++ b/nova/cloudpipe/pipelib.py
@@ -0,0 +1,102 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2010 Anso Labs, LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+CloudPipe - Build a user-data payload zip file, and launch
+an instance with it.
+
+"""
+
+import logging
+import os
+import tempfile
+import base64
+from zipfile import ZipFile, ZIP_DEFLATED
+
+from nova import exception
+from nova import flags
+from nova.auth import users
+from nova import utils
+from nova.endpoint import api
+
+FLAGS = flags.FLAGS
+
+flags.DEFINE_string('boot_script_template',
+ utils.abspath('cloudpipe/bootscript.sh'),
+ 'Template for script to run on cloudpipe instance boot')
+
+class CloudPipe(object):
+ def __init__(self, cloud_controller):
+ self.controller = cloud_controller
+ self.manager = users.UserManager.instance()
+
+ def launch_vpn_instance(self, project_id):
+ logging.debug( "Launching VPN for %s" % (project_id))
+ project = self.manager.get_project(project_id)
+ # Make a payload.zip
+ tmpfolder = tempfile.mkdtemp()
+ filename = "payload.zip"
+ zippath = os.path.join(tmpfolder, filename)
+ z = ZipFile(zippath, "w", ZIP_DEFLATED)
+
+ z.write(FLAGS.boot_script_template,'autorun.sh')
+ z.close()
+
+ key_name = self.setup_keypair(project.project_manager_id, project_id)
+ zippy = open(zippath, "r")
+ context = api.APIRequestContext(handler=None, user=project.project_manager, project=project)
+
+ reservation = self.controller.run_instances(context,
+ # run instances expects encoded userdata, it is decoded in the get_metadata_call
+ # autorun.sh also decodes the zip file, hence the double encoding
+ user_data=zippy.read().encode("base64").encode("base64"),
+ max_count=1,
+ min_count=1,
+ instance_type='m1.tiny',
+ image_id=FLAGS.vpn_image_id,
+ key_name=key_name,
+ security_groups=["vpn-secgroup"])
+ zippy.close()
+
+ def setup_keypair(self, user_id, project_id):
+ key_name = '%s%s' % (project_id, FLAGS.vpn_key_suffix)
+ try:
+ private_key, fingerprint = self.manager.generate_key_pair(user_id, key_name)
+ try:
+ key_dir = os.path.join(FLAGS.keys_path, user_id)
+ if not os.path.exists(key_dir):
+ os.makedirs(key_dir)
+ with open(os.path.join(key_dir, '%s.pem' % key_name),'w') as f:
+ f.write(private_key)
+ except:
+ pass
+ except exception.Duplicate:
+ pass
+ return key_name
+
+ # def setup_secgroups(self, username):
+ # conn = self.euca.connection_for(username)
+ # try:
+ # secgroup = conn.create_security_group("vpn-secgroup", "vpn-secgroup")
+ # secgroup.authorize(ip_protocol = "udp", from_port = "1194", to_port = "1194", cidr_ip = "0.0.0.0/0")
+ # secgroup.authorize(ip_protocol = "tcp", from_port = "80", to_port = "80", cidr_ip = "0.0.0.0/0")
+ # secgroup.authorize(ip_protocol = "tcp", from_port = "22", to_port = "22", cidr_ip = "0.0.0.0/0")
+ # except:
+ # pass