Skip to content

Commit

Permalink
Merge pull request openedx-unsupported#6039 from eduNEXT/mfe/native_i…
Browse files Browse the repository at this point in the history
…nstallation

Create role to deploy MFE for native installations
  • Loading branch information
Fred Smith committed Sep 28, 2020
2 parents c64803b + 6f8c1bd commit e8aa440
Show file tree
Hide file tree
Showing 13 changed files with 400 additions and 1 deletion.
14 changes: 13 additions & 1 deletion playbooks/openedx_native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@
vars:
migrate_db: "yes"
EDXAPP_PREVIEW_LMS_BASE: '{{ EDXAPP_LMS_BASE }}'
EDXAPP_LOGIN_REDIRECT_WHITELIST: [ "{{ EDXAPP_CMS_BASE }}" ]
EDXAPP_LOGIN_REDIRECT_WHITELIST: [
"{{ EDXAPP_CMS_BASE }}",
"account.{{ EDXAPP_LMS_BASE }}",
"gradebook.{{ EDXAPP_LMS_BASE }}",
"profile.{{ EDXAPP_LMS_BASE }}"
]
EDXAPP_LMS_BASE_SCHEME: http
COMMON_LMS_BASE_URL: "{{ EDXAPP_LMS_BASE_SCHEME }}://{{ EDXAPP_LMS_BASE }}"
EDXAPP_LMS_NGINX_PORT: '80'
EDX_PLATFORM_VERSION: 'master'
# Set to false if deployed behind another proxy/load balancer.
Expand Down Expand Up @@ -109,3 +115,9 @@
when: not COMMON_ENABLE_DATADOG
- role: user_retirement_pipeline
when: COMMON_RETIREMENT_SERVICE_SETUP
- role: mfe
MFE_NAME: profile
- role: mfe
MFE_NAME: gradebook
- role: mfe
MFE_NAME: account
130 changes: 130 additions & 0 deletions playbooks/roles/mfe/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
MFE_NAME: ' NOT-SET '
MFE_REPO: 'frontend-app-{{ MFE_NAME }}'
MFE_HOME: '{{ COMMON_APP_DIR }}/{{ MFE_NAME }}'
MFE_USER: '{{ MFE_NAME }}'

MFE_GIT_PROTOCOL: '{{ COMMON_GIT_PROTOCOL }}'
MFE_GIT_DOMAIN: '{{ COMMON_GIT_MIRROR }}'
MFE_GIT_PATH: '{{ COMMON_GIT_PATH }}'
MFE_VERSION: 'master'
MFE_GIT_IDENTITY: null

MFE_CODE_DIR: '{{ MFE_HOME }}/{{ MFE_REPO }}'
MFE_NODEENV_DIR: '{{ MFE_HOME }}/nodeenvs/{{ MFE_NAME }}'
MFE_NODEENV_BIN: '{{ MFE_NODEENV_DIR }}/bin'
MFE_NODE_MODULES_DIR: '{{ MFE_CODE_DIR }}/node_modules'
MFE_NODE_BIN: '{{ MFE_NODE_MODULES_DIR }}/.bin'
MFE_NODE_VERSION: '12.13.1'
MFE_NPM_VERSION: '6.12.1'

MFE_DEBIAN_PKGS_DEFAULT:
- gettext
- nodeenv
MFE_DEBIAN_PKGS_EXTRA: []
MFE_DEBIAN_PKGS: '{{ MFE_DEBIAN_PKGS_DEFAULT + MFE_DEBIAN_PKGS_EXTRA }}'

MFE_CORS_ALLOWLIST: []
MFE_ALLOW_CORS_HEADERS: false
MFE_MAX_WEBSERVER_UPLOAD: !!null
MFE_ALLOW_CORS_CREDENTIALS: false

MFE_HOSTNAME: '~^((stage|prod)-)?{{ MFE_NAME }}.*'
MFE_NGINX_PORT: '80'
MFE_NGINX_READ_TIMEOUT: !!null

MFE_SSL_NGINX_PORT: '443'
MFE_ENABLE_BASIC_AUTH: false

MFE_REPOS:
- PROTOCOL: '{{ MFE_GIT_PROTOCOL }}'
DOMAIN: '{{ MFE_GIT_DOMAIN }}'
PATH: '{{ MFE_GIT_PATH }}'
REPO: '{{ MFE_REPO }}.git'
VERSION: '{{ MFE_VERSION }}'
DESTINATION: '{{ MFE_CODE_DIR }}'
SSH_KEY: '{{ MFE_GIT_IDENTITY }}'

MFE_NODE_ENV: production
MFE_BASE: "{{ MFE_NAME }}.{{ COMMON_LMS_BASE_URL }}"
MFE_BASENAME: "/"
MFE_BASE_SCHEMA: "http"
MFE_BASE_URL: "{{ MFE_BASE_SCHEMA }}://{{ MFE_BASE }}"
MFE_LMS_BASE_URL: "{{ COMMON_LMS_BASE_URL }}"
MFE_LOGIN_URL: "{{ MFE_LMS_BASE_URL }}/login"
MFE_LOGOUT_URL: "{{ MFE_LMS_BASE_URL }}/logout"
MFE_SITE_NAME: ""
MFE_MARKETING_SITE_BASE_URL: "{{ MFE_LMS_BASE_URL }}"
MFE_CONTACT_URL: "{{ MFE_MARKETING_SITE_BASE_URL }}/contact"
MFE_CSRF_TOKEN_API_PATH: "/csrf/api/v1/token"
MFE_REFRESH_ACCESS_TOKEN_ENDPOINT: "{{ MFE_LMS_BASE_URL }}/login_refresh"
MFE_DATA_API_BASE_URL: "{{ MFE_LMS_BASE_URL }}"
MFE_ACCESS_TOKEN_COOKIE_NAME: "{{ COMMON_JWT_AUTH_COOKIE_HEADER_PAYLOAD }}"
MFE_SUPPORT_URL: "{{ MFE_MARKETING_SITE_BASE_URL }}/contact"
MFE_OPEN_SOURCE_URL: "{{ MFE_MARKETING_SITE_BASE_URL }}/opensource"
MFE_TERMS_OF_SERVICE_URL: "{{ MFE_MARKETING_SITE_BASE_URL }}/tos"
MFE_PRIVACY_POLICY_URL: "{{ MFE_MARKETING_SITE_BASE_URL }}/privacy"

MFE_FACEBOOK_URL: ""
MFE_TWITTER_URL: ""
MFE_YOU_TUBE_URL: ""
MFE_LINKED_IN_URL: ""
MFE_REDDIT_URL: ""

MFE_APPLE_APP_STORE_URL: ""
MFE_GOOGLE_PLAY_URL: ""

MFE_ENTERPRISE_MARKETING_URL: "{{ MFE_MARKETING_SITE_BASE_URL }}"
MFE_ENTERPRISE_MARKETING_UTM_SOURCE: ""
MFE_ENTERPRISE_MARKETING_UTM_CAMPAIGN: ""
MFE_ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM: ""

MFE_ECOMMERCE_BASE_URL: https://ecommerce.example.com
MFE_ORDER_HISTORY_URL: https://order-history.example.com
MFE_USER_INFO_COOKIE_NAME: edx-user-info

MFE_NEW_RELIC_APP_ID: 'fake_app'
MFE_NEW_RELIC_LICENSE_KEY: 'fake_license'

MFE_ENVIRONMENT_default:
PATH: '{{ MFE_NODEENV_BIN }}:{{ ansible_env.PATH }}'
NODE_ENV: "{{ MFE_NODE_ENV }}"
BASE_URL: "{{ MFE_BASE_URL }}"
BASENAME: "{{ MFE_BASENAME }}"
LMS_BASE_URL: "{{ MFE_LMS_BASE_URL }}"
LOGIN_URL: "{{ MFE_LOGIN_URL }}"
LOGOUT_URL: "{{ MFE_LOGOUT_URL }}"
SITE_NAME: "{{ MFE_SITE_NAME }}"
MARKETING_SITE_BASE_URL: "{{ MFE_MARKETING_SITE_BASE_URL }}"
CONTACT_URL: "{{ MFE_CONTACT_URL }}"
CSRF_TOKEN_API_PATH: "{{ MFE_CSRF_TOKEN_API_PATH }}"
REFRESH_ACCESS_TOKEN_ENDPOINT: "{{ MFE_REFRESH_ACCESS_TOKEN_ENDPOINT }}"
DATA_API_BASE_URL: "{{ MFE_DATA_API_BASE_URL }}"
ACCESS_TOKEN_COOKIE_NAME: "{{ MFE_ACCESS_TOKEN_COOKIE_NAME }}"
SUPPORT_URL: "{{ MFE_SUPPORT_URL }}"
OPEN_SOURCE_URL: "{{ MFE_OPEN_SOURCE_URL }}"
TERMS_OF_SERVICE_URL: "{{ MFE_TERMS_OF_SERVICE_URL }}"
PRIVACY_POLICY_URL: "{{ MFE_PRIVACY_POLICY_URL }}"
FACEBOOK_URL: "{{ MFE_FACEBOOK_URL }}"
TWITTER_URL: "{{ MFE_TWITTER_URL }}"
YOU_TUBE_URL: "{{ MFE_YOU_TUBE_URL }}"
LINKED_IN_URL: "{{ MFE_LINKED_IN_URL }}"
REDDIT_URL: "{{ MFE_REDDIT_URL }}"
APPLE_APP_STORE_URL: "{{ MFE_APPLE_APP_STORE_URL }}"
GOOGLE_PLAY_URL: "{{ MFE_GOOGLE_PLAY_URL }}"
ENTERPRISE_MARKETING_URL: "{{ MFE_ENTERPRISE_MARKETING_URL }}"
ENTERPRISE_MARKETING_UTM_SOURCE: "{{ MFE_ENTERPRISE_MARKETING_UTM_SOURCE }}"
ENTERPRISE_MARKETING_UTM_CAMPAIGN: "{{ MFE_ENTERPRISE_MARKETING_UTM_CAMPAIGN }}"
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM: "{{ MFE_ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM }}"
ECOMMERCE_BASE_URL: "{{ MFE_ECOMMERCE_BASE_URL }}"
ORDER_HISTORY_URL: "{{ MFE_ORDER_HISTORY_URL }}"
USER_INFO_COOKIE_NAME: "{{ MFE_USER_INFO_COOKIE_NAME }}"
NEW_RELIC_LICENSE_KEY: '{{ MFE_NEW_RELIC_LICENSE_KEY }}'
NEW_RELIC_APP_ID: '{{ MFE_NEW_RELIC_APP_ID }}'


# NOTE: This should be overridden by inheriting MFE-specific role.
MFE_ENVIRONMENT_EXTRA: {}
MFE_ENVIRONMENT: '{{ MFE_ENVIRONMENT_default | combine(MFE_ENVIRONMENT_EXTRA) }}'

MFE_NPM_OVERRIDES: []
14 changes: 14 additions & 0 deletions playbooks/roles/mfe/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
dependencies:
- common
- role: add_user
user_name: "{{ MFE_USER }}"
user_home: "{{ MFE_HOME }}"
group_name: "{{ common_web_group }}"
- role: git_clone
repo_owner: "{{ MFE_USER }}"
repo_group: "{{ common_web_group }}"
GIT_REPOS: "{{ MFE_REPOS }}"
git_home: "{{ MFE_HOME }}"
when: MFE_REPOS is defined

120 changes: 120 additions & 0 deletions playbooks/roles/mfe/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
#
# edX Configuration
#
# github: https://github.com/edx/configuration
# wiki: https://openedx.atlassian.net/wiki/display/OpenOPS
# code style: https://openedx.atlassian.net/wiki/display/OpenOPS/Ansible+Code+Conventions
# license: https://github.com/edx/configuration/blob/master/LICENSE.TXT
#
#
#
# Tasks for role mfe
#
# Overview:
#
# This role performs the operations needed to deploy a MFE
# in a single server.
#
# Example play:
#
# Rather than being included in the play, this role
# is included as a dependency by other roles in the meta/main.yml
# file. The including role should add the following
# depency definition.
#
# dependencies:
# - role: mfe
# MFE_BASE: "{{ PROFILE_MFE_BASE }}"
# MFE_BASE_URL: "{{ PROFILE_BASE_URL }}"
# MFE_NAME: "{{ PROFILE_REPO_NAME }}"
# MFE_SITE_NAME: "{{ PROFILE_SITE_NAME }}"
# MFE_APP_VERSION: "{{ PROFILE_VERSION }}"
# MFE_NODE_VERSION: "{{ PROFILE_NODE_VERSION }}"



- name: install needed packages
apt:
name: "{{ MFE_DEBIAN_PKGS }}"
state: present
update_cache: true
cache_valid_time: 3600
tags:
- install
- install:system-requirements

- name: create nodeenv
command: "nodeenv {{ MFE_NODEENV_DIR }} --node={{ MFE_NODE_VERSION }} --prebuilt"
args:
creates: "{{ MFE_NODEENV_DIR }}"
become_user: "{{ MFE_USER }}"
environment: "{{ MFE_ENVIRONMENT }}"
tags:
- install
- install:system-requirements

- name: upgrade npm
command: "npm install -g npm@{{ MFE_NPM_VERSION }}"
become_user: "{{ MFE_USER }}"
environment: "{{ MFE_ENVIRONMENT }}"
tags:
- install
- install:system-requirements

- name: install npm dependencies
shell: "npm install --dev --no-save"
args:
chdir: "{{ MFE_CODE_DIR }}"
become_user: "{{ MFE_USER }}"
environment: "{{ MFE_ENVIRONMENT }}"
tags:
- install
- install:app-requirements

- name: install npm overrides
npm:
name: "{{ MFE_NPM_OVERRIDES }}"
path: "{{ MFE_CODE_DIR }}"
become_user: "{{ MFE_USER }}"
environment: "{{ MFE_ENVIRONMENT }}"
when: MFE_NPM_OVERRIDES | bool
tags:
- install
- install:app-requirements

- name: build MFE
command: "npm run build"
args:
chdir: "{{ MFE_CODE_DIR }}"
become_user: "{{ MFE_USER }}"
environment: "{{ MFE_ENVIRONMENT }}"
tags:
- install:base


- name: Copying nginx configs for the service
template:
src: "edx/app/nginx/sites-available/app.j2"
dest: "{{ nginx_sites_available_dir }}/{{ MFE_NAME }}"
owner: root
group: "{{ common_web_user }}"
mode: 0640
when: nginx_app_dir is defined
notify: reload nginx
tags:
- install:base
- install:vhosts

- name: Creating nginx config links for the service
file:
src: "{{ nginx_sites_available_dir }}/{{ MFE_NAME }}"
dest: "{{ nginx_sites_enabled_dir }}/{{ MFE_NAME }}"
state: link
owner: root
group: root
when: nginx_app_dir is defined
notify: reload nginx
tags:
- install:base
- install:vhosts
35 changes: 35 additions & 0 deletions playbooks/roles/mfe/templates/edx/app/nginx/sites-available/app.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#
# {{ ansible_managed }}
#

server {
server_name {{ MFE_HOSTNAME }};
listen {{ MFE_NGINX_PORT }};

{% if NGINX_ENABLE_SSL %}
{% include "concerns/handle-ip-disclosure.j2" %}
rewrite ^ https://$host$request_uri? permanent;
{% else %}
{% if NGINX_REDIRECT_TO_HTTPS %}
{% include "concerns/handle-tls-terminated-elsewhere-ip-disclosure.j2" %}
{% include "concerns/handle-tls-terminated-elsewhere-redirect.j2" %}
{% endif %}
{% include "concerns/mfe-common.j2" %}
{% endif %}

{% include "concerns/mfe.j2" %}
}

{% if NGINX_ENABLE_SSL %}
server {
server_name {{ MFE_HOSTNAME }};
listen {{ MFE_SSL_NGINX_PORT }} ssl;
ssl_certificate /etc/ssl/certs/{{ NGINX_SSL_CERTIFICATE|basename }};
ssl_certificate_key /etc/ssl/private/{{ NGINX_SSL_KEY|basename }};
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

{% include "concerns/mfe-common.j2" %}

{% include "concerns/mfe.j2" %}
}
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% if MFE_ENABLE_BASIC_AUTH|bool %}
satisfy any;

allow 127.0.0.1;

{% for cidr in COMMON_BASIC_AUTH_EXCEPTIONS %}
allow {{ cidr }};
{% endfor %}

deny all;

auth_basic "Restricted";
auth_basic_user_file {{ nginx_htpasswd_file }};

index index.html
proxy_set_header X-Forwarded-Proto https;
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# If you are changing this be warned that it lives in multiple places
# there is a TLS redirect to same box, and a TLS redirect to externally terminated TLS
# version of this in nginx and in mfe role.

{% if NGINX_ALLOW_PRIVATE_IP_ACCESS %}
# This regexp matches only public IP addresses.
if ($host ~ "(\d+)(?<!10)\.(\d+)(?<!192\.168)(?<!172\.(1[6-9]|2\d|3[0-1]))\.(\d+)\.(\d+)") {
{% else %}
if ($host ~ "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") {
{% endif %}
return 403;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

# If you are changing this be warned that it lives in multiple places
# there is a TLS redirect to same box, and a TLS redirect to externally terminated TLS
# version of this in nginx and in mfe role.

{% if NGINX_ALLOW_PRIVATE_IP_ACCESS %}
# This regexp matches only public IP addresses.
if ($host ~ "(\d+)(?<!10)\.(\d+)(?<!192\.168)(?<!172\.(1[6-9]|2\d|3[0-1]))\.(\d+)\.(\d+)") {
{% else %}
if ($host ~ "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}") {
{% endif %}
set $test_ip_disclosure A;
}

if ($http_x_forwarded_for != "") {
set $test_ip_disclosure "${test_ip_disclosure}B";
}

if ($test_ip_disclosure = AB) {
return 403;
}
Loading

0 comments on commit e8aa440

Please sign in to comment.