PythonAnywhere Forums

inbound IP for AWS/EC2 security

My PA app connects to a database hosted at Amazon's RDS. I am trying to add security to the database by restricting inbound IP addresses, using EC2 VPS Security Groups (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html#vpc-security-groups)

I need to supply the Source IP, in CIDR notation. What should I set it to, so that all my PyAnywhere apps can access (read/write) the database?

Our IP addresses can change, but I think you can specify an EC2 VPC security group as an alternative -- if so, try using sg-4043273d.

It seems you must be "peered" to share security groups across accounts.

EC2-VPC: A different security group for the same VPC or a peer VPC in a VPC peering connection.

I can send a peer request, but I'd need to know your account ID and VPC ID. Given that you probably want to keep these to yourself, I will assume that we won't be peering. However if it's something you are willing to do (or even just try it out) you can send me a message offline. Thanks.

Hmm, the peering thing doesn't sound quite ideal.

Do you need to access the database from scheduled tasks? Or is it just from the code that's running as the web server, or in consoles? If you don't need to access it from scheduled tasks, it actually looks like we might be able to give you a list of IP addresses that would work right now.

The problem is that we might have to add IPs to that list in the future. It's hard to see a good way we could give you advance notification of changes like that...

Hmm, the peering thing doesn't sound quite ideal.

I agree and don't want to ask any special favors... you guys really do a good job already.

I only need access from the web app itself, not scheduled tasks or console. What about pinging my app's URL, would that be the same IP address or are there proxies/load balancers/etc in between?

From the outside you would be seeing the load balancer ip.

From within the webapp you may be able to run something like this to get the IP.

But again, the IP may change if the webapp is put on a different server/a new server is added etc.

I agree with bfg, the ipinfo.io site will definitely get the right IP address for a web server -- but of course, it might change over time. We can send you a list of the IPs currently in use for your website, but new ones might have to be added in future as we scale up our systems...

Here's a thought: let users schedule a short script using the AWS command-line client, like:

aws ec2 authorize-security-group-ingress --group-id sg-00000000 --protocol tcp --port 22 --cidr cidr $(curl -s ipinfo.io/ip)/32

Is it feasible (or wise) to make the AWS command-line client available for bash scripts? Users could schedule it to run hourly, keeping security lockouts to a minimum.

Is this an idea that could work?

(example from https://realguess.net/2014/12/27/revoke-and-grant-public-ip-addresses-to-amazon-ec2-instances-via-aws-command-line-interface-cli/)

do you mean you want to add the ip to your own aws security group for your own aws db? that's possible (just use your own credentials to add the ip to your aws account).

Hmm, that's clever! Yes, I think something like that might work. It wouldn't work if you did it as a scheduled task, as those run on a different server. But you could put something in your WSGI file that used the Python boto module to have the same effect. Your WSGI file is executed whenever your web app starts up, so if your site was moved from one server to another, when it started up it would auto-authorise itself.

Let me try to put together some sample code.

OK, if you put the following (changing the security group ID, the region, and the auth parameters) at the top of your WSGI file, everything should work fine:

import boto.ec2
import requests

ip = requests.get("http://ipinfo.io/ip").content.strip()
print("Authorising {!r}".format(ip))

conn = boto.ec2.connection.EC2Connection(
    aws_access_key_id="AUTH_KEY",
    aws_secret_access_key="AUTH_SECRET_KEY",
    region=boto.ec2.get_region("REGION")  # eg. us-east-1
)

groups = conn.get_all_security_groups(group_ids=["sg-GROUP_ID"])
if len(groups) == 1:
    group = groups[0]
    group.authorize(
        ip_protocol="tcp", from_port=3306, to_port=3306, cidr_ip="{}/32".format(ip)
    )

This is great -- using boto, which is already installed, eliminates the need for the command-line client. And adding it to the WSGI file will prevent downtime.

For users with multiple apps -- can I run this on just one app? Would my apps ever exist on different PA servers?

Yes, it's quite likely that different apps would be running on different servers in our cluster -- I'd recommend putting it in the WSGI file for all of them.