Flask on Elastic Beanstalk with SSL gives 403 Forb

2019-08-09 17:00发布

问题:

Here is the application directory structure.

  • app/__init_.py
  • app/static/
  • app/models/
  • app/views/
  • application.py
  • requirements.txt
  • .elasticbeanstalk/config
  • .elasticbeanstalk/optionsettings.application_name
  • .ebextensions/python.config
  • .ebextensions/https.config

Here are the snippets of files inside .elasticbeanstalk

#config
EnvironmentTier=WebServer::Standard::1.0
EnvironmentType=SingleInstance
Region=us-west-1
ServiceEndpoint=https://elasticbeanstalk.us-west-1.amazonaws.com
SolutionStack=64bit Amazon Linux 2014.03 v1.0.3 running Python

#optionsettings.application_name
[aws:elasticbeanstalk:container:python]
NumProcesses=1
NumThreads=15
StaticFiles=/static/=app/static/
WSGIPath=application.py

[aws:elasticbeanstalk:container:python:staticfiles]
/static/=app/static/

Here is the steps I took to create SSL certificate from CheapSSL

  • openssl genrsa 2048 > privatekey.pem
  • openssl req -new -key privatekey.pem -out csr.pem
  • Made SSL certificate request to Comodo and received three files
    • Root CA Certificate - AddTrustExternalCARoot.crt
    • Intermediate CA Certificate - PositiveSSLCA2.crt
    • Your PositiveSSL Certificate - server.crt

Note: I specified the server to be Apache/OpenSSL

Lastly, here are the snippets of files inside .ebextensions

#https.config
Resources:
  sslSecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupName: {Ref : AWSEBSecurityGroup}
      IpProtocol: tcp
      ToPort: 443
      FromPort: 443
      CidrIp: 0.0.0.0/0

packages:
  yum:
    mod24_ssl : []

files:
  /etc/httpd/conf.d/ssl.conf:
    mode: 000777
    owner: ec2-user
    group: ec2-user
    content: |
      LoadModule ssl_module modules/mod_ssl.so
      Listen 443
      <VirtualHost *:443>
        <Proxy *>
          Order deny,allow
          Allow from all
        </Proxy>
        SSLEngine on
        SSLCertificateFile "/etc/pki/tls/certs/server.crt"
        SSLCertificateKeyFile "/etc/pki/tls/certs/server.key"

        Alias /static /opt/python/current/app/
        <Directory /opt/python/current/app/>
        Order allow,deny
        Allow from all
        </Directory>

        WSGIScriptAlias / /opt/python/current/app/python/application.py

        <Directory /opt/python/current/app/>
        Order allow,deny
        Allow from all
        </Directory>

        WSGIDaemonProcess wsgi-ssl processes=1 threads=15 display-name=%{GROUP} \
          python-path=/opt/python/current/app:/opt/python/run/venv/lib/python2.6/site-packages user=wsgi group=wsgi \
          home=/opt/python/current/app
        WSGIProcessGroup wsgi
      </VirtualHost>

  /etc/pki/tls/certs/server.crt:
    mode: 000777
    owner: ec2-user
    group: ec2-user
    content: |
      -----BEGIN CERTIFICATE-----
      #contents from server.crt
      -----END CERTIFICATE-----


  /etc/pki/tls/certs/server.key:
    mode: 000777
    owner: ec2-user
    group: ec2-user
    content: |
      -----BEGIN RSA PRIVATE KEY-----
      #contents from privatekey.pem
      -----END RSA PRIVATE KEY-----

This config is a snippet from AWS Elastic Beanstalk documentation with small changes. http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/SSLPython.SingleInstance.html

  • mod_ssl -> mod24_ssl due to yum install error. I was lucky to find this fix from Github
  • 01killhttpd excluded. After going through deploying application multiple times, killing httpd left permanent damage to the application.

The symptom is the following.

  • Can access to http:
  • Gives 403 Forbidden You don't have permission to access / on this server. for https:

I will disclose the site address if necessary.

I have taken every step specified in AWS Documentation but still failed to achieve a single goal; hooking my site with https. There aren't enough posts available online to help me figure this out. I stayed away from Load Balancer because I purchased domain using GoDaddy and it's too complicated to set up domain for lb (That's another story).

Here is the link to the snapshot of Elastic Beanstalk Log.

https://dl.dropboxusercontent.com/u/23288606/Log.txt

Thanks in advance.

Update:

Someone read the logs and pointed out an error message stating this.

[ssl:warn] [pid 1989] AH01909: [ec2-address].compute.amazonaws.com:443:0 server certificate does NOT include an ID which matches the server name

So yeah, SSL certificate refers to my custom domain while the server still thinks of it as ec2's default Public DNS (I think).

FYI, the custom domain is purchased from Godaddy. I made it so that A Record points to my ec2 ip address.

In short, how do I make it so that when my ec2 server sets up ssl, it knows its fqdn is my custom domain, not the one provided by ec2?

回答1:

WARNING: I'm a developer, not a sys admin and I have no idea what I am doing.

This week I had the exact same problems. Including the domain one. Here is a configuration that worked for me. Feedback is welcomed since I just hacked this togheter.

Resources:
  sslSecurityGroupIngress: 
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupName: {Ref : AWSEBSecurityGroup}
      IpProtocol: tcp
      ToPort: 443
      FromPort: 443
      CidrIp: 0.0.0.0/0

packages:
  yum:
    mod24_ssl : []

files:
  /etc/httpd/conf.d/ssl.conf:
    mode: "000755"
    owner: root
    group: root
    content: |
      LoadModule ssl_module modules/mod_ssl.so
      Listen 443
      <VirtualHost *:443>
        <Proxy *>
        Require all granted
        </Proxy>
        SSLEngine on
        SSLCertificateFile "/etc/pki/tls/certs/server.crt"
        SSLCertificateChainFile "/etc/pki/tls/certs/inter.crt"
        SSLCertificateKeyFile "/etc/pki/tls/certs/server.key"

        Alias /static /opt/python/current/app/printwithme/static
        <Directory /opt/python/current/app/>
        Order allow,deny
        Allow from all
        </Directory>

        WSGIScriptAlias / /opt/python/current/app/application.py

        <Directory /opt/python/current/app/>
        Require all granted
        </Directory>

        WSGIDaemonProcess wsgi-ssl processes=1 threads=15 display-name=%{GROUP} \
          python-path=/opt/python/current/app:/opt/python/run/venv/lib/python2.6/site-packages user=wsgi group=wsgi \
          home=/opt/python/current/app
        WSGIProcessGroup wsgi-ssl
      </VirtualHost>

  /etc/pki/tls/certs/server.crt:
    mode: "000400"
    owner: root
    group: root
    content: |
      -----BEGIN CERTIFICATE-----

      -----END CERTIFICATE-----

  /etc/pki/tls/certs/server.key:
    mode: "000400"
    owner: root
    group: root
    content: |
      -----BEGIN RSA PRIVATE KEY-----

      -----END RSA PRIVATE KEY-----

  /etc/pki/tls/certs/inter.crt:
    mode: "000400"
    owner: root
    group: root
    content: |
      -----BEGIN CERTIFICATE-----

      -----END CERTIFICATE-----

container_commands:
  01killhttpd:
    command: "killall httpd"
  02waitforhttpddeath:
    command: "sleep 3"

Add first I thought the forbidden problems had to do with file permissions. Which I think is why OP has his permissions set to 777. In my case it had to do with Apache versions. Amazon uses Apache 2.2 in their example but have 2.4 in the servers. Confirm that by running httpd -v. If this is true then see this link. Which gave me my changes in <Proxy *> and <Directory /opt/python/current/app/>. I don't know the difference between Order deny,allow and Order allow,deny, which I now know are called access controls. If I changed them wrong please let me know. Then I received 404 errors.

After changing that I had to change:

WSGIScriptAlias / /opt/python/current/app/python/application.py

to

WSGIScriptAlias / /opt/python/current/app/application.py

This should point to the file where you create your application object. Your's might be different.

Then had to change:

Alias /static /opt/python/current/app/

to

Alias /static /opt/python/current/app/my-app-name/static

because in my app the static files are in nested folder. This should point to the directory with your. Notice my-app-name is a variable to be changed by you if needed.

Lastly I added a chain file. This was given to me by the SSL people with my certificate. You might need to add it too. In my understanding it might be optional but not really.

Sorry if I missed anything.

Update

I had issues with the file modes. I had to quote them: mode: "000755" mode: "000400"

I will update the configuration to reflect these changes.



回答2:

These don't match:

    WSGIDaemonProcess wsgi-ssl processes=1 threads=15 display-name=%{GROUP} \
      python-path=/opt/python/current/app:/opt/python/run/venv/lib/python2.6/site-packages user=wsgi group=wsgi \
      home=/opt/python/current/app
    WSGIProcessGroup wsgi

You possibly should have:

    WSGIProcessGroup wsgi-ssl

for that directive.