在 10 分钟内实现安全的 React + Docker

做者:Matt Raible

翻译:疯狂的技术宅html

原文:https://scotch.io/tutorials/r...前端

未经容许严禁转载node

假如你已经构建了一个 React 应用,可是如今须要部署它。应该怎么作?首先,最好选择一个云提供商,由于它们通常成本低并且部署容易。react

大多数云提供商都提供了一种部署静态站点的方法。用 React 构建应用只是 JavaScript、HTML 和 CSS。它们是静态文件,几乎能够在任何 Web 服务器上使用。但实际上,若是你使用了 JSX(JS 中的 HTML)和样式化组件,那么这些能够说只有 JavaScriptnginx

Docker 是用于构建和共享容器化应用的事实标准。你可使用它打包你的应用程序,并包含多种开源 Web 服务器来为你的应用程序提供服务。另外,你还能够经过配置网络服务器来发送安全标头,这样使你的程序更安全。git

前提条件:程序员

建立 React 应用

为了集中精力,我用了一位同事已经构建的程序。首先克隆存储库。github

git clone https://github.com/oktadeveloper/okta-react-styled-components-example.git react-docker
cd react-docker
npm install

这是一个使用样式化组件的 React 应用,并由 OpenID Connect(aka OIDC)保护。你能够在使用样式化组件构建 React 应用 一文中了解其建立方式。web

登陆你的 Okta 开发者账户(你已经建立了一个,对吗?)注册此应用并启用 OIDC 身份验证。面试

  1. 转到顶部菜单中的 Applications
  2. 选择 Add Application > Single-Page App ,而后单击 Next
  3. 在设置屏幕上,为你的应用命名,例如 React Docker
  4. 确保端口设置为 3000,而且 Login redirect URIhttp://localhost:3000/callback
  5. 点击 Done

出现的界面将为你提供一个客户端 ID。

image.png

将客户端 ID 复制并粘贴到应用程序的 src/App.js 中。 <yourIssuerURI> 的值能够在 Okta 仪表板的 API > Authorization Servers 下找到。例如个人是 https://dev-133320.okta.com/oauth2/default

function App() {
  return (
    <Router>
      <Security issuer='<yourIssuerURI>'
                clientId='<yourClientId>'
                redirectUri={window.location.origin + '/callback'}
                pkce={true}>
        <SecureRoute path='/' exact={true} component={Calendar}/>
        <Route path='/callback' component={LoginCallback}/>
      </Security>
    </Router>
  );
}

<> 括号只是占位符,请确保将其删除!

npm start 启动你的应用。你将被重定向到 Okta 进行身份验证,而后返你的应用。若是你没有重定向,那是由于你已经登陆。请在 private 窗口中重试来查看登陆过程。

你会看到一个简单、干净的日历,并选择了今天的日期。

image.png

我认可这是一个很是简单的应用,但咱们会用它来演示如何用 Docker 进行容器化。

为何要使用Docker?

你可能会问:“为何要用 Docker?这不会使事情复杂化吗?”

是的我赞成。用 Docker 进行操做比用 Heroku 进行 firebase deploygit push 处理更为复杂。可是若是你真的要使事情复杂化,并用 Kubernetes 去管理你的应用,那么它能够给你更多的控制权。 😛

建立Dockerfile和Nginx配置

在你的根目录中建立一个 Dockerfile

FROM node:14.1-alpine AS builder

WORKDIR /opt/web
COPY package.json package-lock.json ./
RUN npm install

ENV PATH="./node_modules/.bin:$PATH"

COPY . ./
RUN npm run build

FROM nginx:1.17-alpine
RUN apk --no-cache add curl
RUN curl -L https://github.com/a8m/envsubst/releases/download/v1.1.0/envsubst-`uname -s`-`uname -m` -o envsubst && \
    chmod +x envsubst && \
    mv envsubst /usr/local/bin
COPY ./nginx.config /etc/nginx/nginx.template
CMD ["/bin/sh", "-c", "envsubst < /etc/nginx/nginx.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"]
COPY --from=builder /opt/web/build /usr/share/nginx/html

这将会构建你的项目并把 Nginx 添加为 Web服务器。它还将安装 envsubst 版本,该版本容许你用环境变量去替换变量,并设置默认值。

在同一目录中建立一个 nginx.config

server {
    listen       ${PORT:-80};
    server_name  _;

    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $$uri /index.html;
    }
}

这个文件把 Nginx 配置为将你的 React 应用做为 SPA(其中全部路由都转到 index.html)并在 80 端口上运行。在 uri 前面有两个 $$,以防止 $uri 被替换为空白值。

用 React 应用构建 Docker 镜像

先执行 docker ps 确保你的 Docker 守护进程正在运行。而后运行如下命令来构建你的 Docker 镜像。 命令中的 react-docker 能够是你想要为镜像命名的任何名字。

docker build -t react-docker .

该过程完成后,你将会看到如下消息的内容:

Successfully built 3211a1255527
Successfully tagged react-docker:latest

运行你的 Docker + React 应用

如今,你能够用 docker run 命令经过 Docker 在端口 3000 上运行 React 应用。

docker run -p 3000:80 react-docker

若是你发现这些 docker 命令很难记住,也能够在 package.json文件中添加几个脚本 。

"docker": "docker build -t react-docker .",
"react-docker": "docker run -p 3000:80 react-docker"

而后就能够用 npm run dockernpm run react-docker 运行了。

很漂亮吧?在短短几分钟内就把你的 React 应用作了 docker 化。 🎉

把将你的 React App 部署到 Heroku

你的应用要直到正式投入生产时才会真正的存在,因此让咱们把它部署到 Heroku。首先我将向你展现怎样不用 Docker 作到这一点。

首先,你须要 一个 Heroku 账户。而后,安装 Heroku CLI

打开终端,登陆你的 Heroku 账户,而后建立一个新应用。

heroku login
heroku create

如今,你应该有了一个新的 heroku Git 远程存储库。能够用 git remote -v 来确认。

在带有安全标头的根目录中建立一个 static.json 文件,并把全部 HTTP 请求重定向到 HTTPS。

{
  "headers": {
    "/**": {
      "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https://*.okta.com;",
      "Referrer-Policy": "no-referrer, strict-origin-when-cross-origin",
      "Strict-Transport-Security": "max-age=63072000; includeSubDomains",
      "X-Content-Type-Options": "nosniff",
      "X-Frame-Options": "DENY",
      "X-XSS-Protection": "1; mode=block",
      "Feature-Policy": "accelerometer 'none'; camera 'none'; microphone 'none'"
    }
  },
  "https_only": true,
  "root": "build/",
  "routes": {
    "/**": "index.html"
  }
}

要读取 “static.json”,你必须用 Heroku static buildpack

把你的更改提交到 Git,添加 Node.js + static buildpack,而后部署 React 应用。

git commit -am "Configure secure headers and static buildpacks"
heroku buildpacks:set heroku/nodejs
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-static.git
git push heroku master

该过程完成后,使用如下方法在浏览器中打开你的应用程序:

heroku open

你将会被重定向到 Okta,可能会看到如下错误:

The 'redirect_uri' parameter must be an absolute URI that is whitelisted in the client app settings.

要解决这个问题,须要修改 Okta 应用,以将你的 Heroku URL 添加为“登陆重定向 URI”。例如https://gentle-peak-37809.herokuapp.com/callback

如今,你应该能够登陆并看到你的应用在 Heroku 上运行了!你能够在 https://securityheaders.com 上验证其安全标头是否正确。

image.png

在这个部署示例中,buildpacks 为你完成了全部工做。可是并不是每一个云提供商都提供 buildpack。这就是须要 Docker 的地方。

把 Docker + React App 部署到 Heroku

当涉及到 Docker 镜像时,Heroku 具备一些出色的功能。若是你的项目有一个 Dockerfile,则能够用 Heroku Container Registry直接部署你的应用。

首先,登陆到Container Registry。

heroku container:login

而后,建立一个新的应用。

heroku create

把 Git URL 做为新的 remote 添加到你的应用。

git remote add docker https://git.heroku.com/<your-app-name>.git

而后,把将你的 Docker 镜像 push 到 Heroku 的 Container Registry。

heroku container:push web --remote docker

该过程完成后,release 你的应用程序镜像:

heroku container:release web --remote docker

而后,在浏览器中打开该应用:

heroku open --remote docker

你须要先在 Okta 中添加应用的 URI,而后才能登陆。

改善 Docker 中 Nginx 的安全标头

若是在 securityheaders.com 上的 Docker 站点中测试新的 Nginx,你的得分应该是 F

为了解决这个问题,修改你的 nginx.config 添加安全头。

server {
    listen       ${PORT:-80};
    server_name  _;

    root /usr/share/nginx/html;
    index index.html;

    location / {
        try_files $$uri /index.html;
    }

    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https://*.okta.com;";
    add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;
    add_header X-XSS-Protection "1; mode=block";
    add_header Feature-Policy "accelerometer 'none'; camera 'none'; microphone 'none'";
}

更新文件后,运行如下命令:

heroku container:push web --remote docker
heroku container:release web --remote docker

如今你应该获得 A

image.png

用 Cloud Native Buildpacks 建立你的 React + Docker 镜像

在本文中,咱们学习了把 React 应用部署到 Heroku 的两种方法。首先是利用 buildpack 和 git push。第二个是使用 Heroku 的 Container Registry 和 heroku container:push + heroku push:release

Cloud Native Buildpacks 是 Pivotal 和 Heroku 在 2018 年初发起的一项举措。它具备 pack CLI,可以让你用 buildpacks 构建 Docker 映像。

个人好朋友 Joe Kutner是 Heroku 的一名软件架构师,在实现 Cloud Native Buildpacks 中发挥了重要的做用。 Joe 是 JHipster 项目的积极提交者,其做者 The Healthy Programmer 是 Cloud Native Buildpacks 核心团队的创始成员 。他对 Docker 的建议是:“若是不须要,请不要使用 Dockerfile”。

Joe 对我在弄清楚如何使用 buildpacks 建立 Docker 映像的技术上提供了很大的帮助,因此下面的说明应该归功于他。

首先,请 installpack。若是你使用的是 Mac 或 Linux,可使用 Homebrew。若是用的是 Windows,能够安装其可执行文件

brew tap buildpack/tap
brew install pack

在前面的 buildpacks 示例中,我用了 Heroku 的 Node.js 和静态 buildpacks。

Heroku 静态构建包不是 “Cloud Native” 构建包。它使用旧的(原生云)API。这意味着它与开箱即用的 pack 不兼容。

幸运的是,Heroku 确实提供了 cnb-shim,你能够用它来使其工做。在用 cnb-shim 转换后,Joe 为 Heroku 的静态 buildpack 建立了一个 URL (https://cnb-shim.herokuapp.com/v1/heroku-community/static) 。

在本地构建和运行 Docker 镜像以前,必须先进行一项更改。 从 static.json 中删除 "https_only":true 这一行。

而后用如下命令经过 Node.js 和静态 buildpack(也就是你在 Heroku 上使用的相同 buildpack)构建 Docker 镜像。

pack build react-pack --builder heroku/buildpacks --buildpack \
  heroku/nodejs,https://cnb-shim.herokuapp.com/v1/heroku-community/static

提示:若是你想摆脱 --builder 参数,能够用 pack set-default-builder heroku/buildpacks

该过程完成后,你应该能够运行它。

docker run --rm -it --init -p 3000:3000 --env PORT=3000 okta

若是你发现这些 pack 命令很难被记住,那么能够把它们添加到 package.json 中。

"pack": "pack build react-pack --builder heroku/buildpacks --buildpack heroku/nodejs,https://cnb-shim.herokuapp.com/v1/heroku-community/static",
"react-pack": "docker run --rm -it --init -p 3000:3000 --env PORT=3000 react-pack"

而后可使用 npm run packnpm run react-pack 来运行它们。

把将你的 React + Docker 镜像部署到 Docker Hub

经过把它们部署到 Docker Hub 等注册表中,能够轻松共享 Docker 容器。若是你尚未 Docker Hub 账户,那就先建立一个

拥有账户以后,登陆并 push 你的镜像。在下面的示例中,我正在使用 react-docker,但你也可使用 react-pack 来部署 buildpacks 版本。

docker login
docker image tag react-docker <your-username>/react-docker
docker push <your-username>/react-docker

默认状况下,这会将其标记为 latest。若是要标记和推送特定版本,能够用:

docker image tag react-docker <your-username>/react-docker:1.0
docker push <your-username>/react-docker

而后其余人就能够用如下命令 pull 并运行:

docker run -p 3000:80 <your-username>/react-docker

把 React + Docker 镜像部署到 Heroku

要把现有映像部署到 Heroku,能够用 docker push。你必须用如下命名约定来标记和推送镜像。

docker tag <image> registry.heroku.com/<app>/<process-type>
docker push registry.heroku.com/<app>/<process-type>

要部署 react-pack 镜像,你能够执行如下操做:

docker tag react-pack registry.heroku.com/fierce-eyrie-08414/web
docker push registry.heroku.com/fierce-eyrie-08414/web
heroku container:release web --remote docker

我尝试了一下,发现没有强制使用 HTTPS。必须将 "https_only":true 添加到 static.json 中,而后从新push。

了解有关 React 和 Docker 的更多信息

在本教程中,咱们学习了如何用 Docker 容器化你的 React 应用。你能够用 docker build 手动进行这项操做,也能够用 Heroku 的 Container Registry 经过 Dockerfile 推送和发布项目。在构建容器时,还能够用 pack 命令来利用 Cloud-Native + Heroku 构建包。

若是你用的是 Heroku,它的 buildpack 比 Docker 更容易使用。经过简单的 git push,你能够在 Heroku 的服务器上部署代码并构建。

能够在 GitHub上 的 oktadeveloper/okta-react-docker-example 上找到本示例的源代码。


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎继续阅读本专栏其它高赞文章:


相关文章
相关标签/搜索