Sunday, March 4, 2018

Pi Zero W Security Cameras Part 2: Internet Accessibility

The best part about breaking the Security Camera blog into parts is that there is a demarcation point of how far the security system can go.  This post explains how to get the system accessible from the internet.  Another nice part of this is that we will be abstracting away from the hardware and away from the operating system.  We will set up an Nginx reverse proxy to our hub from part 1, verify web connectivity, and verify that we can reach it from the internet.  There are some options on how to do this, and a few warnings.  First up is that the instructions will be for building an Nginx container.  I am using instructions for Portainer.io as the management console instead of command line to make the instructions more accessible to the masses.  I am running my container from a virtual machine that I have set up in my environment, but you can add the containers to one of the cameras or a physical system in your own environment.

This will be broken down into a few parts, you should be able to verify that each part worked properly before continuing on.  

Parts

1. Hub configuration and container setup
2. DuckDNS
3. Nginx configuration and SSL certificate

Hub configuration and container setup

Log into the MotionEye Hub and select one of your cameras from the drop down.  In the settings, select Video Streaming.  Enable the streaming with basic authentication.  Add a password and change the name of the surveillance user.  Apply the settings and go to the url in the Video Streaming menu, using the surveillance username and password to login.  I have not had any luck with digest authentication in apps or through a browser when enabling it on the MotionEye hub.

Video Streaming

We now get to add our containers into the mix.  Go to your system that you intend on running containers from and install docker.  Once the docker engine is running, you can perform the command "docker pull portainer/portainer" to get the latest portainer image.  You then execute the container with "docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer".  You can now access portainer by going to the url http://ip-address-of-docker-host:9000.  Setup the admin account and login to the dashboard.  There's an amazing amount of functionality in this container, some of which will be covered in a future blog about the basics of establishing a secure container environment.  For now, we are going to use it as is.

Aggregate 1

Install the Nginx container by going to the Containers tab and selecting "Add container".  Give it a name you will recognize on the top line, and add the official image by adding nginx:latest in the image configuration.  At the bottom, under "Restart policy", change it to "Unless stopped". Under "Actions" select the "Deploy the container" button. You should now see your Nginx container running in the Container menu.  If you click the name of your container, you can access the console of the container to look around at what is inside of it.  If you have any issues pulling the container, we will cover that in the Nginx configuration section.

Nginx Setup

DuckDNS

In order to get a working certificate and easily reach your home system, you will need a domain name.  Fortunately, you can just tag along as a sub domain of DuckDNS for free.  The real problem that I've noticed is coming up with a unique namespace.  For the benefit of the reader, we will pretend that aggknow.duckdns.org was not taken and use that throughout the article.  Go ahead and log in to http://www.duckdns.org with whichever account you want, or create a persona account. Once you have logged in, type in the sub domain that you would like, and see how many tries it takes to get one that wasn't already taken.  After you have the sub domain, click the install button on the top of the page.  This is where they did the world an enormous favor.  You select your sub domain from a drop down under the "first step" text and determine where you want to set it up.  Once you select your preferred method, scroll down and follow the instructions to get it updating regularly.


Rubber Ducky

A little consideration when setting this up, you probably only need one sub domain.  If you need more than the free tier of 5 sub domains, you are probably working with cloud based websites.  Once you have DNS working, you can forward whatever ports you want to your router and reach them through the internet using your DuckDNS address (although I would limit the number of forwarded ports to only what you absolutely need).  So don't get bogged down trying to think up a unique name for every computer you have, you only need one sub domain name.

Nginx configuration and SSL certificate

We will need to write out the Nginx configuration and add it to our host in order to have a working website.  We will also need SSL certificates in order to have a proper security configuration.  Let's begin with explaining the SSL certification method.  This will be a containerized LetsEncrypt application.  It will renew the certificates for you, which is very helpful.  The issue that I have found is that you can get blocked very quickly from the LetsEndrypt server if you do not set up your configuration correctly.  You get 5 chances before you are locked out for an hour.  So double and triple check your configuration prior to starting the modified containers.

You will need to create 4 volumes on portainer:

1. certs
2. conf.d
3. html
4. vhost.d

The certs directory is where the certificates will eventually end up.  Pay attention to permissions when we connect these to our containers.  The conf.d directory is where you put the code for Nginx to execute.  Because containers are static, you have to add volumes for anything you want to change and keep persistent through reboots.  The html directory is the basic "welcome to Nginx" splash screen default, but you can add html pages to serve out in here.  It is also where LetsEncrypt places it's challenge to validate the domain before issuing a certificate.  The vhost.d volume is where the challenges are replied to from other containers, and I'm fairly certain that we are not using it.  Add the volumes in the Volumes menu on portainer.

I'm going to cover the commands and instructions as well as possible, but almost everything was extracted from the following aggregates.

Aggregate 2
Proxy companion instructions

Aggregate 3
Nginx config starter

Aggregate 4
Another Nginx config example

If you had trouble installing Nginx, "docker pull nginx" on the command line of your docker host should get you the latest official release of that container.  We can now create the container in portainer quickly without adding another registry to the configuration.  Give the container a name that you will recognize, start to type the name of the Nginx container you pulled and select the auto-filled name, or turn off the Nginx container you built and select Duplicate/Edit in that containers menu (double click the container).  Select mapping an additional two ports, 80 on host to 80 on container and 443 on host to 443 on container.  You will also need to forward these ports on your router to your docker host.  You can kill the router port forwarding on port 80 after you get your certificates.

In the Volumes menu at the bottom:

1. html to /usr/share/nginx/html
2. certs to /etc/nginx/certs (as read only)
3. conf.d to /etc/nginx/conf.d
4. vhost.d to /etc/nginx/vhost.d
5. bind /var/run/docker/sock to /tmp/docker.sock

In the Env menu add LETSENCRYPT_HOST variable name with your domain name as the value.  Add LETSENCRYPT_EMAIL variable name with your email as the value.  The domain name should look like this in the value: aggknow.duckdns.org,www.aggknow.duckdns.org
You should be able to start the container without much issue at this point.  You should now be able to modify the file on the docker host at /var/lib/docker/volumes/conf.d/_data/default.conf to the following aggregate.  For the first run you will comment out lines 3-6 and make sure line 2 is uncommented. 

Aggregate 5
Nginx config

We will need to pull the container for our LetsEncrypt companion.  From the command line of your docker host: "docker pull jrcs/letsencrypt-nginx-proxy-companion" will get you the latest version of the container.  Go through the same portainer setup of a new container, give it a name and start to type out the container name.  You will add the same volumes with 2 big differences.  You will not map conf.d and certs will not be read only.  Start the container, double click it and select the logs button under the start time.  The Diffie-Helman generation can take a few minutes.  Keep your eyes on the stderr logs.  If anything went wrong, hit Google and leave a comment on the blog of what the error was.  It might also be worthwhile to reboot the Nginx container and watch the logs on both of the containers.  If you generated the certificates, it's time to implement them.

From the docker host, edit the file /var/lib/docker/volumes/conf.d/_data/default.conf and comment out line 2.  Uncomment lines 3-6, replacing the certificate and key with what you have at /var/lib/docker/volumes/certs/_data/"your domain name .crt and .key", stop forwarding port 80 on your router, then restart the Nginx container.  Verify you can reach your cameras by going to https://your.domain.name/camera-name and use the surveillance username and password to log in.

There are plenty of apps that you can use to rapidly connect to your cameras through your phone.  Some are paid and offer bells and whistles, others are free and have advertising on the top and bottom of the stream.  Just keep in mind that some of the apps will require authentication every time you select which camera you would like to view.  As usual, be vigilant about permissions when adding the application.  An app that is used to log into a remote website with credentials should not require access to your call history or wireless settings.  Check the ratings, install info,  and if you feel especially security minded, perform a packet sniff on the app to see what it does when it is running.

I apologize for not including the steps to access the cameras from Amazon devices in this blog.  It turns out that I am waiting for a few things to update as well.  The Alexa developer console has changed format and the documentation is currently for the previous version.  So, until there is a reliable form of Amazon documentation, the Amazon devices instructions will be a work in progress.

3 comments:

  1. Awesome post. thanks for sharing this knowledge reviewworldist

    ReplyDelete
  2. I haven’t any word to appreciate this post.....Really i am impressed from this post....the person who create this post it was a great human..thanks for shared this with us. Alarms in Parramatta

    ReplyDelete

3d design for printing

I don't want to sound like an idiot.  I really don't.  I just lack the patience to learn Blender.  It's not just because the nam...