{ "info": { "author": "Manheim", "author_email": "tooling@manheim.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Console", "Environment :: No Input/Output (Daemon)", "Environment :: Web Environment", "Framework :: Twisted", "Intended Audience :: Information Technology", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Security", "Topic :: System :: Networking", "Topic :: Utilities" ], "description": "vault-redirector-twisted\n========================\n\nPython/Twisted application to redirect Hashicorp Vault client requests to the active node in a HA cluster.\n\n.. image:: https://img.shields.io/pypi/v/vault-redirector.svg\n :target: https://pypi.python.org/pypi/vault-redirector\n :alt: PyPi package version\n\n.. image:: https://img.shields.io/github/issues/manheim/vault-redirector-twisted.svg\n :alt: GitHub Open Issues\n :target: https://github.com/manheim/vault-redirector-twisted/issues\n\n.. image:: http://www.repostatus.org/badges/latest/active.svg\n :alt: Project Status: Active \u2013 The project has reached a stable, usable state and is being actively developed.\n :target: http://www.repostatus.org/#active\n\n.. image:: https://secure.travis-ci.org/manheim/vault-redirector-twisted.png?branch=master\n :target: http://travis-ci.org/manheim/vault-redirector-twisted\n :alt: travis-ci for master branch\n\n.. image:: https://codecov.io/github/manheim/vault-redirector-twisted/coverage.svg?branch=master\n :target: https://codecov.io/github/manheim/vault-redirector-twisted?branch=master\n :alt: coverage report for master branch\n\n.. image:: https://readthedocs.org/projects/vault-redirector-twisted/badge/?version=latest\n :target: https://readthedocs.org/projects/vault-redirector-twisted/?badge=latest\n :alt: sphinx documentation for latest release\n\nAPI Documentation: `http://vault-redirector-twisted.readthedocs.org/en/latest/ `_\n\nStatus\n------\n\nThis application is currently very young. Please ensure it meets your needs before using it in production.\n\n**NOTE:** My initial plan was to implement this in Go. My Go knowledge is severely lacking, and the performance of Python/Twisted at 1,000 requests per second is within 25% of the Go variant. Please consider this package to be temporary, until work on the Go version (`https://github.com/manheim/vault-redirector `_) continues.\n\nPurpose\n-------\n\nThere's a bit of a gap in usability of `Vault `_ in a `High Availability `_ mode, at least in AWS:\n\n* Vault's HA architecture is based on an active/standby model; only one server can be active at a time, and any others are standby. Standby servers respond to all API requests with a 307 Temporary Redirect to the Active server, but can only do this if they're unsealed (in the end of the `HA docs `_: \"It is important to note that only unsealed servers act as a standby. If a server is still in the sealed state, then it cannot act as a standby as it would be unable to serve any requests should the active server fail.\").\n* HashiCorp recommends managing infrastructure individually, i.e. not in an auto-scaling group. In EC2, if you want to run Consul on the same nodes, this is an absolute requirement as Consul requires static IP addresses in order for disaster recovery to work without downtime and manual changes.\n\nAs a result, we're left with a conundrum:\n\n1. We can't put Vault behind an Elastic Load Balancer, because that would cause all API requests to appear to have the ELB's source IP address. Not only does this render any of the IP- or subnet-based authorization methods unusable, but it also means we lose client IPs in the audit logs (which is likely a deal-breaker for anyone concerned with security).\n2. The only remaining option for HA, at least in AWS, is to use Route53 round-robin DNS records that have the IPs of all of the cluster members. This poses a problem because if one node in an N-node cluster is either offline or sealed, approximately 1/N of all client requests will be directed to that node and fail.\n\nWhile it would be good for all clients to automatically retry these requests, it appears that most client libraries (and even the ``vault`` command line client) do not currently support this. While retry logic would certainly be good to implement in any case, it adds latency to retrieving secrets (in the common case where the cluster is reachable, but some nodes are down) and also does not account for possible DNS caching issues. Furthermore, we're providing Vault as a service to our organization; relying on retries would mean either adding retry logic to every Vault client library and getting those changes merged, or deviating from our plan of \"here's your credentials and endpoint, see the upstream docs for your language's client library.\"\n\nThe best solution to this problem would be for `Vault issue #799 `_, a request to add `PROXY Protocol `_ support to Vault, to be completed. Both `AWS ELBs `_ and HAProxy support this, and it would alleviate issue #1 above, allowing us to run Vault behind a load balancer but still have access to the original client IP address.\n\nThis small service is intended to provide an interim workaround until that solution is implemented.\n\nFunctionality\n-------------\n\nWe take advantage of Vault's 307 redirects (and the assumption that any protocol-compliant client library will honor them). Instead of connecting directly to the Vault service, clients connect to a load-balanced daemon running on the Vault nodes. This daemon asynchronously polls Consul for the health status of the Vault instances, and therefore knows the currently-active Vault instance at all times. All incoming HTTP(S) requests are simply 307 redirected to the active instance. As this service can safely be load balanced, it will tolerate failed nodes better than round-robin DNS. Since it redirects the client to the active node, the client's IP address will be properly seen by Vault.\n\nRequirements\n------------\n\n1. Python 2.7, 3.3, 3.4 or 3.5 and ``pip``; `virtualenv `_ is recommended.\n2. ``gcc`` or another suitable C compiler and the python headers/development package for your OS; the ``twisted`` package has dependencies with native extensions which must be compiled at install time.\n3. The `twisted `_ package (will be installed automatically via ``pip``).\n4. The `requests `_ package (will be installed automatically via ``pip``).\n5. If you wish to use TLS for incoming connections (highly recommended), the `pyOpenSSL `_ and `pem `_ packages. These can be automatically installed along with vault-redirector by using ``pip install vault-redirector[tls]``.\n6. `Consul `_ running and configured with service checks for Vault (see below)\n7. Vault 0.6.0+\n\nConsul Service Checks\n++++++++++++++++++++++\n\nIn order to determine the active Vault instance, ``vault-redirector`` requires that Consul be running and monitoring the health of all Vault instances. Redirection can be to either the IP address or Consul node name running the active service.\n\nThe current implementation in this package requires Vault 0.6.0+, which automatically\nregisters its own service and health checks with Consul.\n\nInstallation\n------------\n\nWe recommend installing inside an isolated virtualenv. If you don't want to do that and would rather install system-wide, simply skip to the last two steps:\n\n1. Ensure that ``gcc`` or another suitable C compiler is installed.\n2. ``virtualenv vault``\n3. ``source vault/bin/activate``\n4. ``pip install vault-redirector``; if you wish to use TLS for incoming connections (highly recommended) you'll also need the ``pyOpenSSL`` and ``pem`` packages, which will be installed automatically if you instead run ``pip install vault-redirector[tls]``\n\nUsage\n-----\n\nCommand Line Usage\n++++++++++++++++++\n\nAll options and configuration are passed in via command-line options.\n\n.. code-block:: console\n\n jantman@exodus$ vault-redirector -h\n usage: vault-redirector [-h] [-v] [-l] [-V] [-S] [-I] [-p POLL_INTERVAL]\n [-P BIND_PORT] [-C CHECKID] [-c CERT_PATH]\n [-k KEY_PATH]\n CONSUL_HOST_PORT\n\n Python/Twisted application to redirect Hashicorp Vault client requests to the\n active node in a HA cluster\n\n positional arguments:\n CONSUL_HOST_PORT Consul address in host:port form\n\n optional arguments:\n -h, --help show this help message and exit\n -v, --verbose verbose output. specify twice for debug-level output.\n See also -l|--log-enable\n -l, --log-disable If specified, disable ALL logging after initial setup.\n This can be changed at runtime via signals\n -V, --version show program's version number and exit\n -S, --https Redirect to HTTPS scheme instead of plain HTTP.\n -I, --ip redirect to active node IP instead of name\n -p POLL_INTERVAL, --poll-interval POLL_INTERVAL\n Consul service health poll interval in seconds\n (default 5.0)\n -P BIND_PORT, --port BIND_PORT\n Port number to listen on (default 8080)\n -C CHECKID, --checkid CHECKID\n Consul service CheckID for Vault (default:\n \"service:vault\"\n -c CERT_PATH, --cert-path CERT_PATH\n Path to PEM-encoded TLS certificate. If you need a\n certificate chain to verify trust, this file should be\n composed of the server certificate followed by one or\n more chain certificates. If specified, you must also\n specify -k|--key-path\n -k KEY_PATH, --key-path KEY_PATH\n Path to PEM-encoded TLS private key. If specified, you\n must also specify -c|--cert-path\n\nBy default, ``vault-redirector`` will redirect clients to the hostname (Consul\nhealth check **node name**) of the active Vault node, over plain HTTP. This can\nbe changed via the ``-I | --ip`` and ``-S | --https`` options.\n\nUsage with TLS\n+++++++++++++++\n\nvault-redirector is capable of listening with TLS/HTTPS, which is strongly\nrecommended as clients will send their authentication tokens as HTTP headers.\nTo do so, specify the ``-k|--key-path`` and ``-c|--cert-path`` options with the\npaths to the key and certificate files, respectively. Each should be a\nPEM-encoded file; if your certificate requires a trust/CA chain to be presented\nto clients, the file at ``cert-path`` should be a combined certificate and chain\nfile, composed of the PEM-encoded certificate concatenated with one or more PEM-encoded\nchain certificates.\n\nRunning as a Daemon / Service\n+++++++++++++++++++++++++++++\n\nFor anything other than testing, ``vault-redirector`` should be run as a system\nservice. There is no built-in daemonizing support; this is left up to your\noperating system.\n\nHere is an example `systemd `_\nservice unit file for ``vault-redirector``, assuming you wish to run it as a\n``vaultredirector`` user and group, and it is installed into a virtualenv at\n``/usr/local/vault-redirector``, and Consul is running on localhost (127.0.0.1)\non port 8500. This will start the service with logging disabled (``-l``) but set\nto INFO level (``-v``); logging can be turned on with SIGUSR1 as described below.\n\n.. code-block:: ini\n\n [Unit]\n Description=Vault Redirector\n Requires=basic.target network.target\n After=basic.target network.target\n\n [Service]\n Type=simple\n User=vaultredirector\n Group=vaultredirector\n PrivateDevices=yes\n PrivateTmp=yes\n ProtectSystem=full\n ProtectHome=read-only\n CapabilityBoundingSet=\n NoNewPrivileges=yes\n ExecStart=/usr/local/vault-redirector/bin/vault-redirector -v -l 127.0.0.1:8500\n RestartSec=5s\n TimeoutStopSec=30s\n Restart=always\n # disable all rate limiting; let it restart forever\n StartLimitInterval=0\n\n [Install]\n WantedBy=multi-user.target\n\nIf you wish to both use TLS for incoming connections and redirect to a HTTPS URL for Vault,\nthe ``ExecStart`` line would be:\n\n.. code-block:: ini\n\n ExecStart=/usr/local/vault-redirector/bin/vault-redirector -v -l -S --cert-path=/path/to/server.crt --key-path=/path/to/server.key 127.0.0.1:8500\n\nHealth Check\n++++++++++++\n\nVault-redirector will respond to a request path of /vault-redirector-health with\na JSON body something like the following; this can be used for load balancer\nhealth checks. If the active vault instance is known, the HTTP status code will\nbe 200. Otherwise (i.e. if there is no active vault node or if Consul is unreachable)\nit will be a 503.\n\n.. code-block:: json\n\n {\n \"healthy\": true,\n \"application\": \"vault-redirector\",\n \"version\": \"0.1.0\",\n \"consul_host_port\": \"127.0.0.1:8500\",\n \"source\": \"https://github.com/manheim/vault-redirector-twisted\",\n \"active_vault\": \"vault_hostname_or_ip:port\",\n \"last_consul_poll\": \"YYYY-MM-DDTHH:MM:SS\"\n }\n\nLogging and Debugging\n---------------------\n\nPython's logging framework can impose a slight performance penalty even for messages\nwhich are below the level set to be displayed (simple testing reports 10x execution\ntime for logging to a level below what's set, vs guarding the log statements with\na conditional). As a result, in addition to Python's normal logging verbosity\nlevels, all logging statements after initial setup are guarded by a global\n\"logging enabled\" boolean; if logging is not enabled, the calls to Python's\nlogging framework will never be made. This behavior can be enabled by running\nthe process with the ``-l`` or ``--log-disable`` options (which is the\nrecommended production configuration).\n\nNote that this functionality is completely separate from the logging module's\nlevels, which are controlled by the ``-v`` / ``-vv`` options (and are not currently\nchangeable at runtime).\n\nAt any time, logging can be enabled by sending SIGUSR1 to the process, or disabled\nby sending SIGUSR2 to the process.\n\nSupport\n-------\n\nPlease open any issues or feature requests in the `manheim/vault-redirector-twisted GitHub issue tracker `_ They will be dealt with as time allows. Please include as much detail as possible, including your version of ``vault-redirector`` and the Python version and OS/distribution it's running on, as well as the command line arguments used when running it. Debug-level logs will likely be very helpful.\n\nDevelopment\n-----------\n\nPull requests are welcome. Please cut them against the ``master`` branch of the `manheim/vault-redirector-twisted `_ repository.\n\nIt is expected that test coverage increase or stay the same, that all tests pass,\nthat any new code have complete test coverage, and that code conforms to `pep8 `_ and passes `pyflakes `_.\n\nAfter making any changes to the code, before submitting a pull request, run ``tox -e docs`` to regenerate the API documentation. Commit any changes to the auto-generated files under ``docs/source``.\n\nInstalling for Development\n++++++++++++++++++++++++++\n\n1. Fork the `manheim/vault-redirector-twisted `_ repository on GitHub.\n\n2. Clone your fork somewhere on your local machine and ``cd`` to the clone:\n\n.. code-block:: bash\n\n $ git clone git@github.com:YOUR-GITHUB-USER/vault-redirector-twisted.git\n $ cd vault-redirector-twisted\n\n3. Add the manheim upstream repository as a git upstream, so you can pull in\n upstream changes, and fetch it:\n\n.. code-block:: bash\n\n $ git remote add upstream https://github.com/manheim/vault-redirector-twisted.git\n $ git fetch upstream\n\n4. Create a virtualenv for testing and running vault-redirector, install\n your local source into it, and install ``tox`` for testing:\n\n.. code-block:: bash\n\n $ virtualenv .\n $ source bin/activate\n $ pip install -e .\n $ pip install tox pyOpenSSL pem\n\n5. Check out a new git branch. If you're working on a GitHub issue you opened, your\n branch should be called \"issues/N\" where N is the issue number.\n\nTesting\n+++++++\n\nTesting is accomplished via `pytest `_ and\n`tox `_. By default tests will be run\nfor Python 2.7, 3.3, 3.4. 3.5 and the documentation. Each supported Python interpreter has two test suites, ``unit`` and ``acceptance``. The ``acceptance`` suite will actually run vault redirector bound to an available port (but with the Consul active node query code mocked out) and make example HTTP requests against it.\n\nTo run the tests locally, with your virtualenv activated, run ``tox -e py-(unit|acceptance)`` where ```` is one of the Python versions in ``tox.ini`` (i.e. \"27\", \"33\", \"34\" or \"35\"). You will need to already have the appropriate Python interpreter version installed on your system. When the tests are run locally, coverage reports will be generated in the ``htmlcov/`` directory.\n\nTo generate documentation locally, run ``tox -e docs``; the HTML output will be in ``docs/build/html``. This must be done after making any code changes, and any changes to the auto-generated files under ``docs/source/`` must be committed.\n\nAutomated testing is accomplished via TravisCI (it's free for any open source project). If you have a TravisCI account linked to your GitHub, you should be able to add your fork for automated testing without any changes to the repository.\n\nMaintenance\n-----------\n\nInstructions for repository maintainers follow:\n\nFixing Issues / Making Changes\n++++++++++++++++++++++++++++++\n\nNote that all commit messages should be of the form ``issue #: ``. When you've verified that the issue is fixed and update ``CHANGES.rst``, your final commit message should be of the form ``fixes #: ``.\n\n1. Follow the instructions above for installing for development.\n2. Cut a new branch named after the GitHub issue (\"issues/ISSUE_NUMBER\").\n3. Make your code changes as needed, and write or update tests. It's preferred that you commit early and often, to make it easier to isolate work that needs improvements.\n4. Run tests locally at least for py27 and py35: ``tox -e py27-unit,py27-acceptance,py35-unit,py35-acceptance``\n5. Examine the test results and the coverage reports in ``htmlcov/`` (the reports will be written for the last-run unit test suite). Iterate until you have full coverage and passing tests.\n6. Run ``tox -e docs`` to generate documentation locally. Examine it for correctness, and commit any changes to the auto-generated files under ``docs/source/``.\n7. Update ``CHANGES.rst`` with a description of your change and a link to the GitHub issue. Commit that.\n8. Push your branch to origin. If you believe it's ready, open a pull request for it.\n\nHandling PRs\n++++++++++++\n\n1. Ensure that all Travis tests are passing for the PR, and that code coverage is still 100% (for all Python versions).\n2. Check out the pull request locally. To do this simply, you can edit ``.git/config`` in your clone of the repository, and under the ``[remote \"origin\"]`` section add the following lines. Then ``git fetch origin`` and you can check out PRs locally like ``git checkout refs/pull/origin/PR_NUM``. Note that this will be read-only.\n\n.. code-block:: ini\n\n fetch = +refs/pull/*/head:refs/pull/origin/*\n\n3. Run ``tox -e docs`` and ensure there are no changes to the auto-generated docs and that they look correct.\n4. Ensure there is an appropriate ``CHANGES.rst`` entry for the changes.\n5. Ensure that ``README.rst``, if it has been changed, renders correctly on GitHub.\n6. If there are any changes to the local repository, cut a new branch locally, commit them, and push it to your fork. You can either ask the original PR author to pull in your changes, or you can close their PR and open a new one for your branch (be sure to reference the closed PR in a comment).\n7. Merge the PR to master.\n\nRelease Process\n+++++++++++++++\n\n1. Open an issue for the release; cut a branch off ``master`` for that issue.\n2. Build docs (``tox -e docs``) and ensure they look correct. Commit any changes to the auto-generated files.\n3. Ensure that Travis tests are passing in all environments.\n4. Ensure that test coverage is no less than the last release (ideally, 100%).\n5. Ensure there are entries in ``CHANGES.rst`` for all changes since the last release, and that they link to the GitHub issues.\n6. Increment the version number in ``vault_redirector/version.py`` and add version and release date to CHANGES.rst. Mention the issue in the commit for this, and push to GitHub.\n7. Confirm that README.rst renders correctly on GitHub.\n8. Upload package to testpypi and confirm that README.rst renders correctly.\n\n * Make sure your ~/.pypirc file is correct (a repo called ``test`` for https://testpypi.python.org/pypi) and that you have ``twine`` installed in your virtualenv. Then:\n * ``rm -Rf dist``\n * ``python setup.py register -r https://testpypi.python.org/pypi``\n * ``python setup.py sdist bdist_wheel``\n * ``twine upload -r test dist/*``\n * Check that the README renders at https://testpypi.python.org/pypi/vault-redirector\n\n9. Create a pull request for the release to be merge into master. Upon successful Travis build, merge it.\n10. Tag the release in Git, push tag to GitHub:\n\n * tag the release. for now the message is quite simple: ``git tag -a X.Y.Z -m 'X.Y.Z released YYYY-MM-DD'``\n * push the tag to GitHub: ``git push origin X.Y.Z``\n\n11. Upload package to live pypi:\n\n * ``twine upload dist/*``\n\n12. make sure any GH issues fixed in the release were closed.\n\nLicense\n-------\n\nvault-redirector is licensed under the MIT license; see ``LICENSE`` for the text of the license.", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/manheim/vault-redirector-twisted", "keywords": "hashicorp vault vaultproject", "license": "", "maintainer": "", "maintainer_email": "", "name": "vault-redirector", "package_url": "https://pypi.org/project/vault-redirector/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/vault-redirector/", "project_urls": { "Homepage": "https://github.com/manheim/vault-redirector-twisted" }, "release_url": "https://pypi.org/project/vault-redirector/0.2.0/", "requires_dist": [ "requests", "twisted (>=16.0.0)", "pem; extra == 'tls'", "pyOpenSSL; extra == 'tls'" ], "requires_python": "", "summary": "Python/Twisted application to redirect Hashicorp Vault client requests to the active node in a HA cluster", "version": "0.2.0" }, "last_serial": 2168797, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "2e4cbd9a28310a9ef745ed33519761d1", "sha256": "8ca6bbfbcd4e1b92b9cd272d693cf9ab6a06dd402e1685e87314459e58854f6e" }, "downloads": -1, "filename": "vault_redirector-0.1.0-py2-none-any.whl", "has_sig": false, "md5_digest": "2e4cbd9a28310a9ef745ed33519761d1", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 47119, "upload_time": "2016-04-15T13:41:11", "url": "https://files.pythonhosted.org/packages/c1/2a/beefb73fd6fb38f2934b2ee62e0472083edfb8f30f3cd9153528584600d7/vault_redirector-0.1.0-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a1c349c1eb6aec83e98b8bdd13b91363", "sha256": "7c8d9705edcba4eda2d4d263a25fd334f5d2b15e31bc1da7acaa1ae1ee4effc1" }, "downloads": -1, "filename": "vault_redirector-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a1c349c1eb6aec83e98b8bdd13b91363", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 47120, "upload_time": "2016-04-15T13:44:17", "url": "https://files.pythonhosted.org/packages/82/f6/6b589e962e1b67793bbf58b221aec76790c27b1ad8f1d33724a26ffe7474/vault_redirector-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "aa00f34e2f57d4d3c958b9c1cdf398e8", "sha256": "6f161a25653845807bcd8f1ae06cd7e8f831938e47cc2b6b9cbaeb23e145d5e2" }, "downloads": -1, "filename": "vault-redirector-0.1.0.tar.gz", "has_sig": false, "md5_digest": "aa00f34e2f57d4d3c958b9c1cdf398e8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29972, "upload_time": "2016-04-15T13:41:17", "url": "https://files.pythonhosted.org/packages/16/8e/d1e9120ccd5f7b5f17bf3022dedcc17313212388e170c5027c38f228e5ce/vault-redirector-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "f192e1cf5359a8dc4c35614e50f2ea7a", "sha256": "ef1f9590e00e2487fe5784f8fe238ecb720527deb5775d7e4b7871e07e6e0b8c" }, "downloads": -1, "filename": "vault_redirector-0.1.1-py27-none-any.whl", "has_sig": false, "md5_digest": "f192e1cf5359a8dc4c35614e50f2ea7a", "packagetype": "bdist_wheel", "python_version": "py27", "requires_python": null, "size": 47758, "upload_time": "2016-04-21T15:36:15", "url": "https://files.pythonhosted.org/packages/1a/0b/e9c440f3665f3097bafbedc095da2d0de63a81cf08b22ab84a7e97ec4643/vault_redirector-0.1.1-py27-none-any.whl" }, { "comment_text": "", "digests": { "md5": "eabf04901bd004f04f317d57bfadc619", "sha256": "0b0fb7110b854f3a0ca7386573bc68eeafd0d48277d4b7d8704f50da7a305df6" }, "downloads": -1, "filename": "vault_redirector-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "eabf04901bd004f04f317d57bfadc619", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 47359, "upload_time": "2016-04-21T15:39:50", "url": "https://files.pythonhosted.org/packages/de/1a/ba760d79a99cf66c688bc3fbf6a1b070dd4f472d746e584cf00fd36f15dd/vault_redirector-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2dba1d57245b00389da7fe32724cad3b", "sha256": "552b05c7886a57e76b652ba3efaa60f209ecaedf5ff716cb8f7eacb2301d23fa" }, "downloads": -1, "filename": "vault-redirector-0.1.1.tar.gz", "has_sig": false, "md5_digest": "2dba1d57245b00389da7fe32724cad3b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30236, "upload_time": "2016-04-21T15:37:22", "url": "https://files.pythonhosted.org/packages/36/8e/64612837b0b912cf6c229f815f55d45e6ccf09a915c5a3010016be0fb92f/vault-redirector-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "022256437ee1a23c55c62957844d67ee", "sha256": "abf3c6d114b3835d260cdb70c0b88cbd9206bd7aef3a132228b32b8daa5d8f76" }, "downloads": -1, "filename": "vault_redirector-0.2.0-py2-none-any.whl", "has_sig": false, "md5_digest": "022256437ee1a23c55c62957844d67ee", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 46958, "upload_time": "2016-06-15T15:04:44", "url": "https://files.pythonhosted.org/packages/bb/90/b4a7dd91e1669b3e328884746f4e88e3137f9241bc91887bcdc6d05500c5/vault_redirector-0.2.0-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "775747cac936a17e48996d2ec9253ee1", "sha256": "cc13ce0962d1d5ef3092cc0f82b95a78aa1679c040121d669706e21e8cbc7e84" }, "downloads": -1, "filename": "vault_redirector-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "775747cac936a17e48996d2ec9253ee1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 46958, "upload_time": "2016-06-15T15:06:43", "url": "https://files.pythonhosted.org/packages/f9/fe/a763043e56142592862c14bebd51021c118509ffb39feeaca003cc19df1d/vault_redirector-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f9455b01018905f82bbf8cf56b5194b4", "sha256": "7591cf078b2cfa9446a338dd1604605d86daf0014da30aae6d90d648b47cbea1" }, "downloads": -1, "filename": "vault-redirector-0.2.0.tar.gz", "has_sig": false, "md5_digest": "f9455b01018905f82bbf8cf56b5194b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30143, "upload_time": "2016-06-15T15:06:14", "url": "https://files.pythonhosted.org/packages/49/fb/00c00fe069eec9f6e80eb902ecb8608670f34f1baa8a9aecc29c0309d218/vault-redirector-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "022256437ee1a23c55c62957844d67ee", "sha256": "abf3c6d114b3835d260cdb70c0b88cbd9206bd7aef3a132228b32b8daa5d8f76" }, "downloads": -1, "filename": "vault_redirector-0.2.0-py2-none-any.whl", "has_sig": false, "md5_digest": "022256437ee1a23c55c62957844d67ee", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 46958, "upload_time": "2016-06-15T15:04:44", "url": "https://files.pythonhosted.org/packages/bb/90/b4a7dd91e1669b3e328884746f4e88e3137f9241bc91887bcdc6d05500c5/vault_redirector-0.2.0-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "775747cac936a17e48996d2ec9253ee1", "sha256": "cc13ce0962d1d5ef3092cc0f82b95a78aa1679c040121d669706e21e8cbc7e84" }, "downloads": -1, "filename": "vault_redirector-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "775747cac936a17e48996d2ec9253ee1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 46958, "upload_time": "2016-06-15T15:06:43", "url": "https://files.pythonhosted.org/packages/f9/fe/a763043e56142592862c14bebd51021c118509ffb39feeaca003cc19df1d/vault_redirector-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f9455b01018905f82bbf8cf56b5194b4", "sha256": "7591cf078b2cfa9446a338dd1604605d86daf0014da30aae6d90d648b47cbea1" }, "downloads": -1, "filename": "vault-redirector-0.2.0.tar.gz", "has_sig": false, "md5_digest": "f9455b01018905f82bbf8cf56b5194b4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30143, "upload_time": "2016-06-15T15:06:14", "url": "https://files.pythonhosted.org/packages/49/fb/00c00fe069eec9f6e80eb902ecb8608670f34f1baa8a9aecc29c0309d218/vault-redirector-0.2.0.tar.gz" } ] }