I'm trying to build a Dockerized CouchDB to run in AWS that bootstraps authentication for my app. I've got a Dockerfile that installs CouchDB 1.6.1 and sets up the rest of the environment the way I need it. However, before I put it on AWS and potentially expose it to the wild, I want to put some authentication in place. The docs show this:
http://docs.couchdb.org/en/1.6.1/api/server/authn.html
which hardly explains the configuration properly or what is required for basic security. I've spent the afternoon reading SO questions, docs and blogs, all about how to do it, but there's no consistent story and I can't tell if what worked in 2009 will works now, or which parts are obsolete. I see a bunch of possible settings in the current ini files, but they don't match what I'm seeing in my web searches. I'm about to start trying various random suggestions I've gleaned from various readings, but thought I would ask before doing trial and error work.
Since I want it to run in AWS I need it to be able to start up without manual modifications. I need my Dockerfile to do the configuration, so using Futon isn't going to cut it. If I need to I can add a script to run on start to handle what can't be done there.
I believe that I need to set up an admin user, then define a role for users, provide a validation function that checks for the proper role, then create users that have that role. Then I can use the cookie authentication (over SSL) to restrict access to my app that provides the correct login and handles the session/cookie.
It looks like some of it can be done in the Dockerfile. Do I need to configure authentication_handlers, and an admin user in the ini file? And I'm guessing that the operations that modify the database will need to be done by some runtime script. Has anyone done this, or seen some example of it being done?
UPDATE:
Based on Kxepal's suggestion I now have it working. My Dockerfile is derived from klaemo's docker-couchdb, as mentioned below. The solution is to force the database to require authentication, but a fresh install starts out as Admin-Party. To stop that you have to create an admin user, which secures the system data but leaves other databases open. First, create an admin user in your Dockerfile:
RUN sed -e '/^\[admins\]$/a admin=openpassword\n' -i /usr/local/etc/couchdb/local.ini
(just following klaemo's sed pattern of using -e) and when CouchDB runs it will salt and hash this password and replace it in the local.ini file. I extract that password and replaced "openpassword" with this so that my Dockerfile didn't have the password in plain text. CouchDB can tell by the form of it not to hash it again.
The normal pattern to now secure the other databases is to create users/roles and use them in a validation function to deny access to the other databases. Since I am only interested in getting a secure system in place for testing I opted to defer this and just use the settings in local.ini to force everyone to be authenticated.
The Dockerfile now needs to set the require_valid_user flag:
RUN sed -e '/^\[couch_httpd_auth\]$/a require_valid_user = true\n' -i /usr/local/etc/couchdb/local.ini
And that requires uncommenting the WWW-Authenticate setting:
RUN sed -e 's/^;WWW-Authenticate/WWW-Authenticate/' -i /usr/local/etc/couchdb/local.ini
Which, since the setting shows Basic realm="administrator" means that the NSURLProtectionSpace in my iOS app needs to use #"administrator" as the realm.
After this I now have a Dockerfile that creates a CouchDB server that does not allow anonymous modification or reading.
This hasn't solved all of my configuration issues since I need to populate a database, but since I use a python script to do that and since I can pass credentials when I run that, I have solved most problems.
To setup auth configuration during image build, you need to check not API, but configuration for server admins. TL;DR just put [admin] section into local.ini file with your username and password in plain text - on start, CouchDB will replace password with it hash and CouchDB wouldn't be in Admin Party state.
P.S. Did you check docker-couchdb project?
Related
I'm trying to restore the database with the maintenance script provided. But there is a check in the script which doesn't allow me to restore if the user is postgres.
Any reason for that ?
It is a custom to not use the postgres user in this case. Similar to the custom that when operating a linux server, you use a user account instead of the root account.
You can remove the passage from the script if you want to proceed anyway. However, cookiecutter-django should have generated a .env/.production/.postgres file with a different username than postgres.
My little podcast backend written in Django contains a ShowModel. I have also written a custom management command to update episodes for each show from an external API.
For ease of use I'd now like to put a button next to the list of shows in the Django admin to be able to update them from there. I know there's call_command() that also takes the argument but I'm getting a bit stuck in how to bring this into the admin area where the shows are already. Also, if possible I'd also pass the output to the web admin.
You can use this lib https://github.com/vint21h/django-mcadmin
Or try to read the code and pull some pieces to your project.
I was solving the same puzzle of running management commands from the admin interface, so here is what I found pip install -i https://test.pypi.org/simple/ django-run-command
This package helps you to run management commands from the admin dashboard
Short Version
Is there any tool that will let me use a single Django admin page to affect multiple Django installations on different servers?
Detailed Version
I've got a bunch of different servers, each with their own Django installation. This works great ... except when I want to do something via the Django admin to all of the servers, in which case I have to log on to each server separately.
For instance, let's say I have a release coming and a co-worker (who's not a programmer) wants to use the admin to make a "message" record about the release for the server's users to see. They have to log in to each server's admin individually, create the message record, then move on to the next server until they've gotten through all of them.
To get around this whenever I have a multi-server change I've been using Git; ie.:
I make a commit with files for the change
I push that commit
I pull that commit on all of the servers at once (using Fabric).
However, this too is sub-optimal, because we can't take advantage of the admin interface, and doing something as simple as adding a "new release coming" message requires an actual (mini-)release itself.
So, it seems to me the best way to handle this would be if there was some sort of meta-admin tool my co-worker could use to Django admin work on multiple servers at once. Does anything like that exist?
I've been using django-auth-ldap for a while to auth against a single server (AUTH_LDAP_SERVER_URI in settings.py). There have been some changes in my organization recently, and I now need to be able to check against two different LDAP servers (actually: Active Directory, but I don't think that comes into play here). Unfortunately there is not a single location that has all of the user info I need.
Is there any way I can configure django-auth-ldap to check against more than 1 server? The documentation seems to assume a single server/URI. I'd also entertain ideas outside of django-auth-ldap, but I'd really like to stick with it if possible because it keeps things simple.
You would need to extend the custom auth handler to take an iterable for servers to check against and just step through them.
There is nothing stopping you from checking any number of directories for the information you need - there is no limitation in the underlying libraries.
django-auth-ldap 1.1 (just released) allows you to easily define multiple subclasses of the authentication backend that use different collections of settings. See http://packages.python.org/django-auth-ldap/#multiple-ldap-configs.
I want to restrict access to all but a few selected files per a user, but if I type: /media/userdocuments/FILENAME django happily spits back the file for even users who aren't logged in. How can I integrate the permission framework to work around this?
Thanks!
EDIT: I realize that the django development server is insecure, so I guess the question is: How would I do that in a production environment with apache, lighttp, etc.
Use RewriteMap along with a script that connects to Django and verifies permissions, rewriting to a "disallowed" URL on auth failure.