Maintain simple private pip repository on S3.
848
Maintain simple private pip repository on S3.
PriPy can serve python packages from an S3 backed API gateway. To set up the private repository you'll need to create a lambda function and make it accessible via API gateway.
The lambda function lists the packages and builds available on S3 and a build can be downloaded directly by the API gateway.
To install the command line utility pripy simple install it with pip
pip install --extra-index-url http://pripy.kayakodev.net/simple/ pripy
and you should have pripy installed on your machine
pripy --help
Setting up the repository consists of 3 steps
Setting up the S3 bucket is easy. Just create a new bucket using S3 console or aws cli
aws --profile <profile> s3 mb pripy.bucket_name
Now create a new IAM role with following policies
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:ListBucket"
],
"Resource": [
pripy.py,
pripy.py
]
},
{
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "*"
}
]
}
After creating the role add following trust relationship configuration
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
This trust relationship lets Lambda and API gateway assume the role.
Save the ARN of the role as it will be required during API Gateway configuration.
The lambda function will be used to list all available packages and their builds. This function will also be responsible to authenticate the user request for us. The function ships with a very simple authentication provider which fetches the list of users and their password from S3 and tries to authenticate the request with it. However, authentication is completely optional and can be turned off if you want the repository to be publicly accessible.
Create a new Lambda function with the IAM role created in previous step. Feel free to choose any name, the example here will assume the name to be PriPy.
Zip __init__.py, api.py file and auth.py and upload it to Lambda, on MacOS X you can do
zip lambda.zip __init__.py api.py auth.py
to generate the zip file.
Configure the lambda handler function to api.handle_lambda.
Finally, add following environment variables
| Variable | Description |
|---|---|
BUCKET_NAME | Name of the S3 bucket that was created in first step |
AUTH_PROVIDER_NAME | Valid values are S3 or NoAuth, choose NoAuth if you don't require authentication |
AUTH_BUCKET_NAME | This option is valid only if S3 authentication provider is chosen. The value of this variable is set to the S3 bucket where the credentials can be found. |
AUTH_PROVIDER_FILE | The file in AUTH_BUCKET_NAME which contains the credentials |
You may also want to make sure that the bucket which contains the credentials is properly secured and lambda function has permission to read the file.
API Gateway is responsible for authenticating the requests with authentication provider, invoking the Lambda function to list available packages and builds and finally serving builds from S3.
The Gateway provides three API endpoints in total.
/simple//simple/{package}/simple/{package}/{build}| Endpoint | Description |
|---|---|
/simple/ | List all available packages |
/simple/{package}/ | List all builds available for a package |
/simple/{package}/{build} | Download a build file |
To set up the API gateway, go to the API gateway console and create a new API set. The example here assumes the name to be pripy.
Inside the API, create three new resources
/simple//simple/{package}//simple/{package}/{build}Path parameter names are important to get right as the lambda function depends on the name of parameters.
Let's setup the methods on these API resources now.
Create a GET method on /simple resource and configure it as follows
| Option | Value |
|---|---|
| Integration Type | Lambda |
| Use Lambda Proxy Integration | Check |
| Lambda Region | Lambda function region |
| Lambda Function | PriPy |
After saving the method, click on Method Request and add a header Authorization.
Create GET method on /simple/{package} and configure it as follows
| Option | Value |
|---|---|
| Integration Type | Lambda |
| Use Lambda Proxy Integration | Check |
| Lambda Region | Lambda function region |
| Lambda Function | PriPy |
After saving the method, click on Method Request and add a header Authorization.
Create GET method on /simple/{package}/{build} and configure it as follows
| Option | Value |
|---|---|
| Integration Type | AWS Service |
| AWS Region | Region of the S3 bucket created in first step |
| AWS Service | Simple Storage Service (s3) |
| AWS Subdomain | Leave |
| HTTP Method | GET |
| Action Type | Use Path Override |
| Path Override | ${stageVariables.bucket}/{package}/{build} |
| Execution Role | ARN of the IAM role created in second step |
| Content Handling | Convert to binary (if needed) |
We are using a stage variable named bucket to route the requests to S3 bucket, this variable will be configured when the API is deployed.
Now go to Integration Request and configure the URL Path Parameters as follows:
| Name | Mapped From |
|---|---|
package | method.request.path.package |
build | method.request.path.build |
Now go back and go to Method Response, expand the row for HTTP Status 200 and add following Response Headers for 200
TimestampContent-TypeContent-LengthGo back again and go to Integration Response, expand the row for method response status 200, set Content handling to Convert to binary (if needed) and add following header mappings:
| Response Header | Mapping Value |
|---|---|
Timestamp | integration.response.header.Date |
Content-Type | integration.response.header.Content-Type |
Content-Length | integration.response.header.Content-Length |
With API endpoints all configured, let's setup the binary support so that we can download the files from S3 via API gateway.
Select Binary Support from left most pane and add content types that you want to be able to download. pripy can push builds in all formats supported by distutil so it is sensible to mark all these formats as binary content.
application/x-tarapplication/x-binaryapplication/octet-streamapplication/zipbinary/octet-streamThe API gateway is now ready to use. The last step is to set up the authentication.
Select pripy API from left most pane and click on Authorizers under it. Configure the authorizer as follows:
| Option | Value |
|---|---|
| Lambda Region | Region of Lambda function |
| Lambda Function | pripy |
| Authorizer Name | Choose a name for authoriser |
| Execution Role | ARN of the IAM role created in first step |
| Identity token source | method.request.header.Authorization |
| Token Validation Expression | Leave empty |
| Result TTL in seconds | A sensible time to live in seconds for authentication results. Set this value to a reasonable number |
Now enable authentication by following these steps:
pripy APIIf you configured the API authentication to use S3 as a backend, make sure the file that is configured to provide credentials exists and contains valid JSON object.
Keys in the JSON object are user names and their corresponding values are the passwords. Example:
{
"user_one": "randompassword",
"user_two": "anotherpassword"
}
API Gateway and Lambda function is now ready for deployment.
Go to API Gateway and select pripy. From actions menu select Deploy API and create a new stage. The example assumes the stage name to be beta.
When the stage is created, select Stage Variables tab and add the stage variable:
| Name | Value |
|---|---|
bucket | s3 bucket name which contains the packages and builds |
You can optionally configure a custom domain name with SSL to serve the repository.
In order to configure a custom domain name you must import the SSL certificate for the domain you want to use into AWS Certificate Manager. You can also request a fresh certificate if you don't have one already.
Select Custom Domain Names from left panel and select Create Custom Domain Name.
Configure the domain name as follows
| Option | Value |
|---|---|
| Domain Name | Domain name you want to use |
| ACM Certificate | SSL Certificate for the domain |
| Path | Leave |
| Destination | Select Pripy API and select active stage |
Copy the Distribution Domain Name that was just generated and configure the DNS records for the domain to point to this distribution.
PriPy also provides a handy command line utility pripy.
The command line can do various tasks to ease the management. For more details please see
pripy --help
It is thoroughly documented and up to date will current state of codebase.
A package which is to be maintained by PriPy must fulfil following requirements:
setup.cfg file. This is a good idea to follow in general because it
makes the setup configuration consumable by external tools. PriPy reads the package information from setup.cfg
file and fails if the file could not be found.setup.cfg file
as major.minor.patch string. Extended version information such as beta or rc are not supported right now.Following commands are available in pripy command line tool:
| Command | Description |
|---|---|
| build | Build source distribution |
| bump | Bump version number |
| publish | Publish a build to pripy |
| sync | Synchronize external packages into pripy |
| user | Add or remove pripy users |
Installing packages with pip is fairly simple. The quickest way is to run
pip install --extra-index-url https://username:[email protected]/simple package_name
Where the URL to API gateway must be substituted for example URL and package_name would be the package you want to install. Username and password can be omitted if authentication is not set up.
Note that the path /simple in the URL is important otherwise pip will not be able to discover any package.
To permanently configure pip to use this repository you must edit ~/.pip/pip.conf and include following:
[install]
extra-index-url = https://username:[email protected]/simple
Now pip will by default look into this repository every time you try to install a package with
pip install package_name
Content type
Image
Digest
Size
270.8 MB
Last updated
almost 9 years ago
docker pull kayako/pripy