Configuring a VPN server using Cloud-Init

vpn
While security groups are a good measure for locking down access to your network through firewall rules, in many cases it is necessary to configure a VPN between your Cloud-A Virtual Private Network and your office / individual computer. This can reduce the number of internet accessible resources and encrypt all of your traffic between sites.

We’re going to launch an Ubuntu 14.04 server and, using Cloud-Init, pre-configure it with the required packages to run your own VPN server. We’ll set up your VPC Firewall in a way to allow VPN traffic into your private network, and establish a connection from your VPN client.

Cloud-init

Cloud-init enables you to leverage OpenStack’s metadata service to send instructions to your instance that will be executed upon launching. In this post, we’re going to leverage this functionality to have cloud-init install and configure our VPN for us on first boot. Here is what the final instruction set will look like:

#cloud-config

packages:
  - pptpd

write_files:
  - content: |
          myvpnuser pptpd mypassword *
    path: /etc/ppp/chap-secrets
  - content: |
          net.ipv4.ip_forward = 1
    path: /etc/sysctl.d/98-ip-forward.conf
  - content: |
          option /etc/ppp/pptpd-options
          localip 192.168.0.1
          remoteip 192.168.0.100-199
    path: /etc/pptpd.conf

runcmd:
  - [ 'iptables', '-t', 'nat', '-A', 'POSTROUTING', '-o', 'eth0', '-j', 'MASQUERADE' ]
  - [ 'iptables-save' ]
  - [ 'sysctl', '-p', '/etc/sysctl.d/98-ip-forward.conf' ]

 

Configuration Overview

The Cloud-Init configuration is driven through the cloud-config YAML file, which is marked by “#cloud-config” being the first line. There is a large section of examples in the Cloud-Init documentation. We’re going to walk through the different sections one at a time, explaining what each does and why it’s required to automate the deployment of your VPN server.

pptpdp

Packages

The first section “packages” will tell cloud-init what to pre-install for us. In this case, we’re going to use PPTP for our VPN connection, which pptpd will handle.

Write Files

Next, in the write_files section, we’re providing configuration files that are required for our VPN to work. You should to change myvpnuser and mypassword to reflect the login credentials that you would like your VPN client(s) to use.

Also, we are creating a virtual network to be used for the VPN service. This is done via the localip and remoteip options in /etc/pptpd.conf. Make sure that these values don’t overlap with your office / home network. Using obscure values like 192.168.183.x instead of 192.168.0.x may be a good idea.

Run CMD

Finally, runcmd is a list of commands that cloud-init will run late in the booting process. For our VPN, we need a simple iptables NAT rule and we need to enable IP forwarding in the Linux kernel, as it will be forwarding your traffic to your Cloud-A network.

Launching our Instance

The launch process is identical to launching a regular instance, with one final step at the end. So, we’re going to run through it quickly.

In our example, we’re going to create a new Ubuntu 14.04 server. Before launching, we’re going to go to the Cloud-Init tab and paste the instruction set that you’ve customized with your own values into the textbox. It will perform validation to ensure your formatting is still valid YAML when you create your VPN server.

Screenshot_2015-05-11_21-36-46

At this point, we’re good to launch our instance! Once it has started, we need to allow PPTP traffic to pass through to the instance.  There is a single TCP port (1723) that needs to be opened. In this example, we’re going to create a separate security group called ‘PPTP‘.

Screenshot_2015-05-11_21-11-33

Next up, we just need to add the security group to our instance and associate a Public IP address. Check the docs for more info on creating and assigning Security Groups.

Connecting to your VPN

Configuring the client is relatively simple, especially if we wish to route all traffic through our VPN connection. However, we’re going to configure our client in “split-tunnel mode“. This means that only traffic that is local to the VPN network (IE your Cloud-A instances) will be routed over the PPTP connection, while all other traffic will route as usual.

Mac OSX

Open your Network Preferences and click on the “+” button under the list of network connections. This will bring up a dialog box which allows you to create a new network connection. Here, we’re going to want to select PPTP VPN and give our new connection a name.

Now we simply need to fill in our Public IP address and our username, click ‘Connect’, apply your changes, and enter your password. You’re now connected to your VPN server!

Next, we’re going to configure split tunneling. Apple doesn’t provide a pretty UI to do this, so we’re going to have to open terminal to do so, running: sudo route add -net 10.0.0.0/24 -interface ppp0

As you can see from your terminal, we’re adding a route to your Cloud-A network (10.0.0.0/24 by default) via the PPTP connection (ppp0). The traceroute tests routing to the Cloud-A virtual router. NOTE: On OSX, the sudo route add... command must be run every time we restart our machine. Otherwise, we will not have split routing into our remote Cloud-A network.

Next Steps

If you want to run office-to-cloud VPN, you’ll need to configure static PPTP on your internal network’s router. This way, you’re always connected to your Cloud-A VMs while you are in the office, and can act as if they’re on your local network. If you are running a router with DDWRT installed, there are some instructions here to get you started.

And there we have it! You have now securely connected into your virtual Cloud-A network. If you have any questions, or require assistance with anything VPN, drop us a message at support@clouda.ca.

BULK STORAGE: CONTAINER API KEYS

We’re excited to announce the public availability of Container-specific API keys for our Bulk Storage service. Our team has developed and deployed this feature, which has been reviewed by OpenStack Swift core developers, to meet the specific application requirements for our customers. This will enable you to develop and deploy more secure applications on Cloud-A infrastructure by shipping with secure, revokable authentication keys.

Technical Overview

This feature will allow developers who leverage our Bulk Storage APIs to deploy more secure applications using access keys specific to the container(s) that each application needs to use. There is no longer a need to embed your Cloud-A authentication information when you deploy. Instead, you can generate secure keys on a per-container basis through the Dashboard with either read-only, or full read & write access — in case you need to give access to a third party to perform read operations on any object in a container.

Additionally, we are contributing the Swift middleware that we’ve developed back to the community! The source is available on our Bitbucket account, along with install instructions for enabling the middleware in your swift-proxy server.

Generating Secure Keys

We have extended our Dashboard to allow you to generate, set and revoke secure keys for all of your Bulk Storage containers from the main container screen. In the list of actions, you’ll now see a “Manage Access” action, which will display the currently-set API keys for the container, and an option to regenerate them. For additional security, the default behaviour is such that containers do not have any access keys set and you’ll need to generate initial keys to enable this feature. For your convenience, dashboard generated keys are prefixed with the permission and first four letters of your container name.

The regeneration function serves to revoke your current container credentials, and generate new secure keys. This will help squelch the threat of any potentially leaked credentials by immediately rejecting all requests using the old keys, and certainly not having to worry about leaked account passwords per the OpenStack Swift default access requirements.

Testing

Now that we have our keys, we can test that they work by using simple curl commands. We will test listing files in a container and downloading a test file by passing our new API key in the headers of the request. Note: It is important you use the Bulk Storage https endpoint if you are on an external network to ensure your headers cannot be read by a third party.

List a container

$ curl -v -H 'X-Container-Meta-Read-Key:read-TEST-dff8555a-8c4d-4541-a629-3b6e7029803a' https://swift.ca-ns-1.clouda.ca:8443/v1/AUTH_(tenant_id)/test
...
< HTTP/1.1 200 OK
< X-Container-Object-Count: 1
< 
    index.html

Download a file

Downloading the index file is just as quick.

$ curl -v -H 'X-Container-Meta-Read-Key:read-TEST-dff8555a-8c4d-4541-a629-3b6e7029803a' https://swift.ca-ns-1.clouda.ca:8443/v1/AUTH_(tenant_id)/test/index.html
...
< HTTP/1.1 200 OK
< Content-Length: 44
< Content-Type: text/html
<
<html>
<body>
<h1>test</h1>
</body>
</html>

Key revocation

And when we revoke the key in the dashboard, attempting the request again will return a 401 Unauthorizederror as expected.

$ curl -v -H 'X-Container-Meta-Read-Key:read-TEST-dff8555a-8c4d-4541-a629-3b6e7029803a' https://swift.ca-ns-1.clouda.ca:8443/v1/AUTH_(tenant_id)/test/index.html
...
< HTTP/1.1 401 Unauthorized
< 
401 Unauthorized: Auth Key invalid

Using Python-SwiftClient

In a deployment scenario, it’s likely that you won’t be using curl to fetch or upload objects. Thepython-swiftclient library is the official OpenStack library used to interact with Swift deployments, including our Bulk Storage service. These examples are using a Python 2.7 REPL.

Download a file

We’ll start by downloading the file we’ve been playing with via curl above using the read-only key, which has full read access to the container, but cannot perform any POST, PUT or DELETE requests. Notice that the second argument to get_object, which is normally the auth token is set to None, as this shared key mechanism is separate from the Keystone authentication backend.

>>> import swiftclient
>>> read_key ='read-TEST-dff8555a-8c4d-4541-a629-3b6e7029803a'
>>> response = swiftclient.get_object(
    'https://swift.ca-ns-1.clouda.ca:8443/v2.0/AUTH_(tenant_id)', 
    None, 
    'test', 
    'index.html', 
    headers={
        'X-Container-Meta-Read-Key': read_key
    })
>>> response[1]
'<html>\n<body>\n<h1>test</h1>\n</body>\n</html>\n'

Upload a file

Uploading a file using the full-key is just as easy, in this example we’ll upload a text file to Bulk Storage and read it back out again using the python-swiftclient library.

>>> import swiftclient
>>> full_key = 'full-TEST-1e1c1fca-16ce-4aba-b89c-3c8b7911d1c4'
>>> swiftclient.put_object(
    'https://swift.ca-ns-1.clouda.ca:8443/v2.0/AUTH_(tenant_id)', 
    container='test', 
    name='another_file.txt', 
    contents='this is a test file', 
    headers={'X-Container-Meta-Full-Key': full_key})
>>> response = swiftclient.get_object(
    'https://swift.ca-ns-1.clouda.ca:8443/v2.0/AUTH_(tenant_id)', 
    None,
    'test', 
    'another_file.txt', 
    headers={
        'X-Container-Meta-Full-Key': full_key
    })
>>> response[1]
'this is a test file'

If you have any questions about how to implement these changes into your application, please don’t hesitate to reach out to our support team. This will be our recommended approach for connecting to Bulk Storage from your application, so we want to ensure you’re feeling comfortable with the new features and using them.

Going Forward

We look forward to seeing all of the new integrations this feature enables for our clients. We’re continuously working and deploying new features to give you a competitive advantage when it comes to the automation of your infrastructure. Our team is committed to building our platform to meet your needs, and contributing the appropriate parts back to the OpenStack community whenever we can. Using OpenStack as a framework has helped us launch the most robust public cloud in Canada, and we’re not stopping there!

See you on the other side!

BULK STORAGE: CONTAINER API KEYS

We’re excited to announce the public availability of Container-specific API keys for our Bulk Storage service. Our team has developed and deployed this feature, which has been reviewed by OpenStack Swift core developers, to meet the specific application requirements for our customers. This will enable you to develop and deploy more secure applications on Cloud-A infrastructure by shipping with secure, revokable authentication keys.

Technical Overview

This feature will allow developers who leverage our Bulk Storage APIs to deploy more secure applications using access keys specific to the container(s) that each application needs to use. There is no longer a need to embed your Cloud-A authentication information when you deploy. Instead, you can generate secure keys on a per-container basis through the Dashboard with either read-only, or full read & write access — in case you need to give access to a third party to perform read operations on any object in a container.

Additionally, we are contributing the Swift middleware that we’ve developed back to the community! The source is available on our Bitbucket account, along with install instructions for enabling the middleware in your swift-proxy server.

Generating Secure Keys

We have extended our Dashboard to allow you to generate, set and revoke secure keys for all of your Bulk Storage containers from the main container screen. In the list of actions, you’ll now see a “Manage Access” action, which will display the currently-set API keys for the container, and an option to regenerate them. For additional security, the default behaviour is such that containers do not have any access keys set and you’ll need to generate initial keys to enable this feature. For your convenience, dashboard generated keys are prefixed with the permission and first four letters of your container name.

The regeneration function serves to revoke your current container credentials, and generate new secure keys. This will help squelch the threat of any potentially leaked credentials by immediately rejecting all requests using the old keys, and certainly not having to worry about leaked account passwords per the OpenStack Swift default access requirements.

Testing

Now that we have our keys, we can test that they work by using simple curl commands. We will test listing files in a container and downloading a test file by passing our new API key in the headers of the request. Note: It is important you use the Bulk Storage https endpoint if you are on an external network to ensure your headers cannot be read by a third party.

List a container

$ curl -v -H 'X-Container-Meta-Read-Key:read-TEST-dff8555a-8c4d-4541-a629-3b6e7029803a' https://swift.ca-ns-1.clouda.ca:8443/v1/AUTH_(tenant_id)/test
...
< HTTP/1.1 200 OK
< X-Container-Object-Count: 1
< 
    index.html

Download a file

Downloading the index file is just as quick.

$ curl -v -H 'X-Container-Meta-Read-Key:read-TEST-dff8555a-8c4d-4541-a629-3b6e7029803a' https://swift.ca-ns-1.clouda.ca:8443/v1/AUTH_(tenant_id)/test/index.html
...
< HTTP/1.1 200 OK
< Content-Length: 44
< Content-Type: text/html
<
<html>
<body>
<h1>test</h1>
</body>
</html>

Key revocation

And when we revoke the key in the dashboard, attempting the request again will return a 401 Unauthorizederror as expected.

$ curl -v -H 'X-Container-Meta-Read-Key:read-TEST-dff8555a-8c4d-4541-a629-3b6e7029803a' https://swift.ca-ns-1.clouda.ca:8443/v1/AUTH_(tenant_id)/test/index.html
...
< HTTP/1.1 401 Unauthorized
< 
401 Unauthorized: Auth Key invalid

Using Python-SwiftClient

In a deployment scenario, it’s likely that you won’t be using curl to fetch or upload objects. Thepython-swiftclient library is the official OpenStack library used to interact with Swift deployments, including our Bulk Storage service. These examples are using a Python 2.7 REPL.

Download a file

We’ll start by downloading the file we’ve been playing with via curl above using the read-only key, which has full read access to the container, but cannot perform any POST, PUT or DELETE requests. Notice that the second argument to get_object, which is normally the auth token is set to None, as this shared key mechanism is separate from the Keystone authentication backend.

>>> import swiftclient
>>> read_key ='read-TEST-dff8555a-8c4d-4541-a629-3b6e7029803a'
>>> response = swiftclient.get_object(
    'https://swift.ca-ns-1.clouda.ca:8443/v2.0/AUTH_(tenant_id)', 
    None, 
    'test', 
    'index.html', 
    headers={
        'X-Container-Meta-Read-Key': read_key
    })
>>> response[1]
'<html>\n<body>\n<h1>test</h1>\n</body>\n</html>\n'

Upload a file

Uploading a file using the full-key is just as easy, in this example we’ll upload a text file to Bulk Storage and read it back out again using the python-swiftclient library.

>>> import swiftclient
>>> full_key = 'full-TEST-1e1c1fca-16ce-4aba-b89c-3c8b7911d1c4'
>>> swiftclient.put_object(
    'https://swift.ca-ns-1.clouda.ca:8443/v2.0/AUTH_(tenant_id)', 
    container='test', 
    name='another_file.txt', 
    contents='this is a test file', 
    headers={'X-Container-Meta-Full-Key': full_key})
>>> response = swiftclient.get_object(
    'https://swift.ca-ns-1.clouda.ca:8443/v2.0/AUTH_(tenant_id)', 
    None,
    'test', 
    'another_file.txt', 
    headers={
        'X-Container-Meta-Full-Key': full_key
    })
>>> response[1]
'this is a test file'

If you have any questions about how to implement these changes into your application, please don’t hesitate to reach out to our support team. This will be our recommended approach for connecting to Bulk Storage from your application, so we want to ensure you’re feeling comfortable with the new features and using them.

Going Forward

We look forward to seeing all of the new integrations this feature enables for our clients. We’re continuously working and deploying new features to give you a competitive advantage when it comes to the automation of your infrastructure. Our team is committed to building our platform to meet your needs, and contributing the appropriate parts back to the OpenStack community whenever we can. Using OpenStack as a framework has helped us launch the most robust public cloud in Canada, and we’re not stopping there!

See you on the other side!