No access to HTTPS endpoint of Employee Directory Application

0

Hi, I try to run the Employee Directory Application just like it is done in AWS Technical Essentials course https://explore.skillbuilder.aws/learn/course/1851/play/85986/aws-technical-essentials, but I'm not able to access the HTTPS endpoint. HTTP one works fine. Any way to fix it?

Here are the inbound rules Enter image description here

I also see a similar topic https://repost.aws/questions/QUtBocRTRtSUu7UFRpSiyxHg/err-connection-refused-when-building-employee-directory-app, but I have Unable to connect error in the browser instead.

Thanks.

Artiom
asked 19 days ago88 views
1 Answer
1

Hello.

Can you confirm that your Flask app is listening on port 443 inside your EC2 instance?
You should be able to confirm this by running the following command after connecting to EC2.
I don't think anything will be displayed if it is not listening on port 443.

sudo lsof -i:443

I checked the course content and found the following command.
In the first place, when you look at the command below, it appears that it is only listening on port 80.

FLASK_APP=application.py /usr/local/bin/flask run --host=0.0.0.0 --port=80

I also looked at the code in "application.py", but even if I access it on port 443, I think an error will occur because no SSL certificate is specified.
Therefore, this code itself is not designed to be accessed via HTTPS.

"Demo Flask application"
import json
import os
import subprocess
import requests

from flask import Flask, render_template, render_template_string, url_for, redirect, flash, g
from flask_wtf import FlaskForm
from flask_wtf.file import FileField
from wtforms import StringField, HiddenField, validators
import boto3

import config
import util

def get_instance_document():
    try:
        r = requests.get("http://169.254.169.254/latest/dynamic/instance-identity/document")
        if r.status_code == 401:
            token=(
                requests.put(
                    "http://169.254.169.254/latest/api/token",
                    headers={'X-aws-ec2-metadata-token-ttl-seconds': '21600'},
                    verify=False, timeout=1
                )
            ).text
            r = requests.get(
                "http://169.254.169.254/latest/dynamic/instance-identity/document",
                headers={'X-aws-ec2-metadata-token': token}, timeout=1
            )
        r.raise_for_status()
        return r.json()
    except:
        print(" * Instance metadata not available")
        return { "availabilityZone" : "us-fake-1a",  "instanceId" : "i-fakeabc" }


if "DYNAMO_MODE" in os.environ:
    import database_dynamo as database
else:
    import database

application = Flask(__name__)
application.secret_key = config.FLASK_SECRET

doc = get_instance_document()
availablity_zone = doc["availabilityZone"]
instance_id = doc["instanceId"]

badges = {
    "apple" : "Mac User",
    "windows" : "Windows User",
    "linux" : "Linux User",
    "video-camera" : "Digital Content Star",
    "trophy" : "Employee of the Month",
    "camera" : "Photographer",
    "plane" : "Frequent Flier",
    "paperclip" : "Paperclip Afficionado",
    "coffee" : "Coffee Snob",
    "gamepad" : "Gamer",
    "bug" : "Bugfixer",
    "umbrella" : "Seattle Fan",
}

### FlaskForm set up
class EmployeeForm(FlaskForm):
    """flask_wtf form class"""
    employee_id = HiddenField()
    photo = FileField('image')
    full_name = StringField(u'Full Name', [validators.InputRequired()])
    location = StringField(u'Location', [validators.InputRequired()])
    job_title = StringField(u'Job Title', [validators.InputRequired()])
    badges = HiddenField(u'Badges')

@application.before_request
def before_request():
    "Set up globals referenced in jinja templates"
    g.availablity_zone = availablity_zone
    g.instance_id = instance_id

@application.route("/")
def home():
    "Home screen"
    s3_client = boto3.client('s3')
    employees = database.list_employees()
    if employees == 0:
        return render_template_string("""
        {% extends "main.html" %}
        {% block head %}
        Employee Directory - Home
        <a class="btn btn-primary float-right" href="{{ url_for('add') }}">Add</a>
        {% endblock %}
        """)
    else:
        for employee in employees:
            try:
                if "object_key" in employee and employee["object_key"]:
                    employee["signed_url"] = s3_client.generate_presigned_url(
                        'get_object',
                        Params={'Bucket': config.PHOTOS_BUCKET, 'Key': employee["object_key"]}
                    )
            except:
                pass

    return render_template_string("""
        {% extends "main.html" %}
        {% block head %}
        Employee Directory - Home
        <a class="btn btn-primary float-right" href="{{ url_for('add') }}">Add</a>
        {% endblock %}
        {% block body %}
            {%  if not employees %}<h4>Empty Directory</h4>{% endif %}

            <table class="table table-bordered">
              <tbody>
            {% for employee in employees %}
                <tr>
                  <td width="100">{% if employee.signed_url %}
                  <img width="50" src="{{employee.signed_url}}" /><br/>
                  {% endif %}
                  <a href="{{ url_for('delete', employee_id=employee.id) }}"><span class="fa fa-remove" aria-hidden="true"></span> delete</a>
                  </td>
                  <td><a href="{{ url_for('view', employee_id=employee.id) }}">{{employee.full_name}}</a>
                  {% for badge in badges %}
                  {% if badge in employee['badges'] %}
                  <i class="fa fa-{{badge}}" title="{{badges[badge]}}"></i>
                  {% endif %}
                  {% endfor %}
                  <br/>
                  <small>{{employee.location}}</small>
                  </td>
                </tr>
            {% endfor %}

              </tbody>
            </table>

        {% endblock %}
    """, employees=employees, badges=badges)

@application.route("/add")
def add():
    "Add an employee"
    form = EmployeeForm()
    return render_template("view-edit.html", form=form, badges=badges)

@application.route("/edit/<employee_id>")
def edit(employee_id):
    "Edit an employee"
    s3_client = boto3.client('s3')
    employee = database.load_employee(employee_id)
    signed_url = None
    if "object_key" in employee and employee["object_key"]:
        signed_url = s3_client.generate_presigned_url(
            'get_object',
            Params={'Bucket': config.PHOTOS_BUCKET, 'Key': employee["object_key"]}
        )

    form = EmployeeForm()
    form.employee_id.data = employee['id']
    form.full_name.data = employee['full_name']
    form.location.data = employee['location']
    form.job_title.data = employee['job_title']
    if 'badges' in employee:
        form.badges.data = employee['badges']

    return render_template("view-edit.html", form=form, badges=badges, signed_url=signed_url)

@application.route("/save", methods=['POST'])
def save():
    "Save an employee"
    form = EmployeeForm()
    s3_client = boto3.client('s3')
    key = None
    if form.validate_on_submit():
        if form.photo.data:
            image_bytes = util.resize_image(form.photo.data, (120, 160))
            if image_bytes:
                try:
                    # save the image to s3
                    prefix = "employee_pic/"
                    key = prefix + util.random_hex_bytes(8) + '.png'
                    s3_client.put_object(
                        Bucket=config.PHOTOS_BUCKET,
                        Key=key,
                        Body=image_bytes,
                        ContentType='image/png'
                    )
                except:
                    pass

        if form.employee_id.data:
            database.update_employee(
                form.employee_id.data,
                key,
                form.full_name.data,
                form.location.data,
                form.job_title.data,
                form.badges.data)
        else:
            database.add_employee(
                key,
                form.full_name.data,
                form.location.data,
                form.job_title.data,
                form.badges.data)
        flash("Saved!")
        return redirect(url_for("home"))
    else:
        return "Form failed validate"

@application.route("/employee/<employee_id>")
def view(employee_id):
    "View an employee"
    s3_client = boto3.client('s3')
    employee = database.load_employee(employee_id)
    if "object_key" in employee and employee["object_key"]:
        try:
            employee["signed_url"] = s3_client.generate_presigned_url(
                'get_object',
                Params={'Bucket': config.PHOTOS_BUCKET, 'Key': employee["object_key"]}
            )
        except:
            pass
    form = EmployeeForm()

    return render_template_string("""
        {% extends "main.html" %}
        {% block head %}
            {{employee.full_name}}
            <a class="btn btn-primary float-right" href="{{ url_for("edit", employee_id=employee.id) }}">Edit</a>
            <a class="btn btn-primary float-right" href="{{ url_for('home') }}">Home</a>
        {% endblock %}
        {% block body %}

  <div class="row">
    <div class="col-md-4">
        {% if employee.signed_url %}
        <img alt="Mugshot" src="{{ employee.signed_url }}" />
        {% endif %}
    </div>

    <div class="col-md-8">
      <div class="form-group row">
        <label class="col-sm-2">{{form.location.label}}</label>
        <div class="col-sm-10">
        {{employee.location}}
        </div>
      </div>
      <div class="form-group row">
        <label class="col-sm-2">{{form.job_title.label}}</label>
        <div class="col-sm-10">
        {{employee.job_title}}
        </div>
      </div>
      {% for badge in badges %}
      <div class="form-check">
        {% if badge in employee['badges'] %}
        <span class="badge badge-primary"><i class="fa fa-{{badge}}"></i> {{badges[badge]}}</span>
        {% endif %}
      </div>
      {% endfor %}
      &nbsp;
    </div>
  </div>
</form>
        {% endblock %}
    """, form=form, employee=employee, badges=badges)

@application.route("/delete/<employee_id>")
def delete(employee_id):
    "delete employee route"
    database.delete_employee(employee_id)
    flash("Deleted!")
    return redirect(url_for("home"))

@application.route("/info")
def info():
    "Webserver info route"
    return render_template_string("""
            {% extends "main.html" %}
            {% block head %}
                Instance Info
            {% endblock %}
            {% block body %}
            <b>instance_id</b>: {{g.instance_id}} <br/>
            <b>availability_zone</b>: {{g.availablity_zone}} <br/>
            <hr/>
            <small>Stress cpu:
            <a href="{{ url_for('stress', seconds=60) }}">1 min</a>,
            <a href="{{ url_for('stress', seconds=300) }}">5 min</a>,
            <a href="{{ url_for('stress', seconds=600) }}">10 min</a>
            </small>
            {% endblock %}""")

@application.route("/info/stress_cpu/<seconds>")
def stress(seconds):
    "Max out the CPU"
    flash("Stressing CPU")
    subprocess.Popen(["stress", "--cpu", "8", "--timeout", seconds])
    return redirect(url_for("info"))

if __name__ == "__main__":
    application.run(debug=True)
profile picture
EXPERT
answered 19 days ago
profile pictureAWS
EXPERT
kentrad
reviewed 18 days ago
  • Indeed, the sudo lsof -i:443 command returns nothing. I wonder how it worked in the video then. Is this a known issue?

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions