【16日目】クラウド環境とセキュリティ【作曲の補助ツールを作るまでの日記】

2023年8月14日~2023年8月21日

色々あって、クラウドサーバーを使わせていただけることになった。
本当にありがとうございます。

Laravelプロジェクトを現在のVM環境からクラウド環境に移行することを目指して、色々学ぶ。これ、いわゆるオンプレ環境からクラウド環境に移行するってやつでは!?

といっても、そもそもクラウドは何となくしかわからないし、セキュリティに関しては知識がほぼ無いのでめちゃんこ怖い。

っていうかまず何からやればいいんだこれ。いきなりSSH接続していいものなのか?

一旦、VMのバックアップを取ろう

本当に何が起こるかわからないので、Virtual Boxのスナップショットを取っておく。

ただそれだけなんだけど、大事だよね。

とりあえず、情報を仕入れる

いきなりSSH接続して色々弄るのは怖くて私にはできないので、一旦色んな情報を仕入れる。

読んでみるのは以下の通り

  • 安全なウェブサイトの作り方
    IPA(情報処理推進機構)が出している無料資料。
    Webサイトを作る上での様々なセキュリティ知識が載っている。
  • この一冊で全部わかる」シリーズ
    超詳しい情報を仕入れるというより、マクロ的・体系的な知識を図も使って理解する感じの本。今回はセキュリティ編とクラウド編。
    実は、Webサイトの環境構築を初めてするときはこのシリーズのサーバー編とWebサイト編を図書館で借りて読んだりしてた。
  • Amazon Web Services基礎からのネットワーク&サーバー構築
    AWSを使ったWebアプリ環境構築本。ハンズオン(実際に手を動かしながら)学ぶ感じ。
    今回のクラウド環境はAWSではないと思うんだけど、同じようなもんなんじゃないかと甘く見ている。
    現在は第4版まで出ているけど、第3版がKindle Unlimited対象だったのでそちらを。

なぜクラウドを使うのか

そもそも、今回なぜクラウドを使うのか。
極論を言えば「クラウド技術を学びたいから」になるんだけど、一般的にどんなメリットがあるのだろうか。

ここでのクラウドはパブリッククラウド(クラウド事業者が不特定多数に提供するクラウド)を指す。

  • 規模の柔軟性
    従量課金制なので初期費用も少なくて済む。
    規模の需要に対し、サーバーを大きくも小さくもできる。
  • 一部責任の転嫁
    クラウド側で用意してくれている部分はある意味その責任を転嫁することができる。責任の転嫁だけでなく、機能の保証ともいえるかも。

    例えば、クラウド側で既にWebサーバーの構築まで提供されているなら、ハードウェアからサーバーまでは変に弄らない限り責任がクラウド側にあることになる。
    しかも、セキュリティアップデートもクラウド側でしてくれるっぽいし、サーバーのリージョンを分散させれば物理的な障害対策にもなる。

    ただし、責任は転嫁できるけど責任を取ってくれるかは契約による。

逆にデメリットはなんだろうか

  • 長期利用を考える場合のコスト
    初期費用が安いのがクラウドの特徴だけど、長期的に考えるとオンプレミスの方が安いこともある。
  • データ消失やサービス停止のリスク
    責任を一部転嫁しているからこそのリスク。
    クラウドとは関係ないけど、Googleのドメインサービスがサービス終了したりと、いつサービスが終了するかはわからない。
    また、クラウド事業者側のミスでデータが消える可能性も無くはない。
  • 自由度の低下
    クラウド側に責任がある部分は弄れないので、その分自由度は下がる。

VMからクラウドに環境を移行する際に何を考慮するか

そもそも、VMのローカル環境からクラウド環境に移ることで何を考慮しなきゃいけないのか。私の場合になるけど、挙げていく。

何を目標にし、どのような手段を踏むか(大雑把)

整理するために書いていく。

目標

今回の場合、目標はVM上のLaravelアプリケーションをクラウド環境で動かすことになる。

“動かす”の定義は、私がブラウザを介してアプリケーションにアクセス、一般的な操作を行える事とする。そのため、不特定多数に公開することは目標としない。

手順

今考えられるVMからCloudに移行する手順を挙げていく

  1. IaaSクラウド環境の契約
    IaaS(Infrastructure as a Service)つまり、ハードウェアだけをクラウドで借りる形。
    OSの導入から自分でやることになる。
    つまり、ハイパーバイザ型のVMと同じような形だよね。
  2. ネットワークの構築
    もちろんネットワーク構築もしなきゃいけない。
    具体的には、クラウドインスタンス自体のネットワーク設定・Webサーバーのネットワーク設定・DBサーバーのネットワーク設定が必要になる。
    ここで、ファイアウォールの設定などもする。
  3. OS・各種アプリケーションの環境構築
    今回も使うOSのAlmaLinuxの導入から、Apache・MySQL・PHPの環境を構築する必要がある。また、その際の設定などは本番環境を想定した設定にする。
    いわゆるLAMP環境の構築ってやつ。
  4. GitでLaravelプロジェクトの取得
    環境構築ができたところでGitからLaravelプロジェクトを取得する。
    けど、gitignoreに入ってるものは移行できないので、他の方法を普通は取るのかもしれない。
  5. テスト
    最後に、アプリケーションがしっかり動くのか、手動でテストする。

恐らく、こんな感じ。

この中でも、1番のIaaSは今回設定していただいているので、2番以降をやっていく感じになるのかなと思うんだけど、ネットワークの構築のところがちょっと疑問なんだよね。とりあえず進めていくか。

通信環境の変化

今までNATを利用してVMからホストPCを経由したネットワーク接続を行っており、ホストオンリーアダプターでホストPCとVMの相互通信を担っていた。
勿論だけど、これがまるっきり変わる。

どう変わるのかはAmazon Web Services基礎からのネットワーク&サーバー構築が結構詳しく解説してくれていた。

クラウド環境の説明は頂いていないので憶測にはなってしまうんだけど、一般的なクラウドネットワークについて説明していく。

クラウドのネットワーク

クラウド(本を参考にしているのでAWS)のネットワークが少し特殊だったので説明しながら理解する。

ネットワークの分割

クラウドネットワーク(主にAWS)は
サブネット∈VPC∈クラウドから提供されたネットワーク
のように分割されている。

つまり、クラウドから提供されたネットワークがVPC(Virtual Private Cloud)で分けられていて、VPCがサブネットで分けられている。

ネットワークを分けるっていうのが凄いイメージしにくくて、どう分けるの? と思うんだけど、ローカルIPアドレスで分けるみたい。

ネットワークの分割方法

IPアドレス(IPv4)は0.0.0.0から255.255.255.255のように、0~255までの256通りの数字が4つ合わさってできている。

つまり、256=2の8乗=8bitが4つで32bitの情報になっている。

この中でローカルIPアドレスとして割り振られているのは

  • 「10.0.0.0~10.255.255.255」
    24bit=2^24=16777216通り
  • 「172.16.0.0~172.31.255.255」
    20bit=2^20=1048576通り
  • 「192.168.0.0~192.168.255.255」
    16bit=2^16=65536通り

となっている。

これらのローカルIPからVPCの分を割り振り、そこからサブネットに割り振る。
つまり、2回に分割することになる。

恐らくここの割り振り方は何でもいいんだけど、一般的な割り振り方は

VPCを10.1.0.0〜10.1.255.255の範囲、つまり16bitの範囲を取得し、
その中のサブマスクは10.1.1.0〜10.1.1.255までの8bitの範囲を取得するみたいな感じ。

もし2個目のサブマスクが出てきたら、10.1.2.0〜10.1.2.255みたいな。

この、10.1.0.0〜10.1.255.255という表記……ちょっと長いよね。
そこで、CIDR(サイダー)表記というのがある。

CIDR表記

CIDRは使うIPアドレスの範囲を表記する方法。

例えば、さっきの「10.1.0.0〜10.1.255.255」は「10.1.0.0/16」と表記し、「10.1.1.0〜10.1.1.255」は「10.1.1.0/24」と表記する。

つまり、何bitまで使わないかをスラッシュの次にある数字で表記する感じ。
厳密に言えばIPアドレスのネットワーク部をスラッシュの次に表記する。

ネットワーク分割のメリット

分けるメリットは、ネットワーク設定の範囲を弄れるところにあるのかなと思う。

例えば、DBサーバーにはそもそも外部から接続できないようにしたい→プライベート設定にしたい。
逆にWebサーバーは外部からアクセスできるようにしたい→パブリック設定にしたい。

こういう時にサブネットでDBは10.1.1.0/24で、Webサーバーは10.1.2.0/24に割り振ると、それぞれのネットワークが独立したものと見なされて、それぞれで設定ができる。

現在のクラウド環境の状況を把握する

とりあえず、何となく分かったので、クラウド環境を弄っていけたらなと思う。

といっても、今回クラウドサービスに関する情報を一切頂いていないので、恐らくネットワークの分割などはせずに環境を構築しろという事だと思う。

つまり、現在の状況は

  • 恐らくIaaSのクラウドサービスを使わせていただいている
  • OSはAlmaLinuxを入れてくれている
  • ネットワーク設定も相互通信できる状態で設定済み
  • SSH接続できるようになっている

という感じ。あんま詳しく書きすぎてもよく無いのである程度に曖昧に。

ということは、アプリケーションの環境構築してgitでデータ持ってくれば目標達成なのでは?
もちろん、設定とかは本番環境用に調整したりはするんだと思うけど。

この場合、DBも外部からアクセスできることになっちゃうんだと思うんだけど、大丈夫なんだろうか。

うーん。やってみないとわからないので、やってみようか。

やってみる

といっても、クラウドのセキュリティに気を付けなきゃいけない環境なので、大雑把に記録していく。

とりあえず、AlmaLinuxを入れただけの状態だったので、vimインストール→ユーザー作成→sudo権限の付与までやった。

アクセスログをみてみよう

ファイアウォールについて調べたり、セキュリティに関して調べてたんだけど、ログを実際に見たら面白そうと思ったので、ログを見てみる。

/var/log/secureで認証系のログを見る

CentOS系であれば、「/var/log/secure」をcatコマンド等で閲覧すれば、sshdやsudoの履歴を閲覧できる。

実際のログを見せるわけにはいかないんだけど、私の場合既に数万件のログがあった。
エグいなこれ。

因みにこれ、ファイアウォールでポートは塞いでいるので、SSH接続用ポートからのみだけのログなんだよね。だから実際はもっと数はあるはず。


ssh接続の試行だけでなく、sudo履歴なども残るので恐らく私だけで数十件のログはあるんだけど、他は全部ボットのSSH接続試行ってことだよね?

誇張なしで毎分接続の試行がされている。こっわいなこれ。
しかも、ログをしっかり見てみると様々なユーザー名で接続を試されていて、ブルートフォース攻撃ってこれのことかぁ……となる。

ログイン履歴ログをみる

そんな毎分アクセスの試行がされていて、実際にログイン突破されていないの? という心配があるので、ログイン履歴も見てみる。

因みに、公開鍵認証でしかログインできないようになっているので、よっぽどのことが無い限りは不正ログインは出来ないはず。

“last”
と打つことで直近の「ログインユーザー」「アクセス日時」「何分ログインしていたか」「どのIPからのログインか」を見ることが出来る。

このログも流石に見せられないけど、私が使い始めてからの接続IPは1つだけなので問題なさそう。ログイン日時も私が使ってた時の日時だし、大丈夫。

ファイアウォール

PCで何かネットワークを弄ろうとすると出てくるこのファイアウォールというもの。

実際、何となくしか分からないので理解したい。

そもそも、ファイアウォールには色々種類がある。
私は”ファイアウォール”という製品があるのかと思ってたんだけど、そうじゃなくAlmaLinuxだったらfirewalldとか、ubuntuだったらiptablesとか。
他にもセキュリティ会社が独自にファイアウォールを作り販売していたりする。

今回、AlmaLinuxに入っているファイアウォールはfirewalldというもの。

こいつは何をしてくれているのだろうか?

AlmaLinuxのファイアウォール「firewalld」は何をしているのか

今までCentOS 6まではiptablesというファイアウォールが使われていて、CentOS 7からはfirewalldというのがデフォルトに。

このfirewalldは内部でiptablesも動かしていて、設定の記述形式がわかりやすくなったバージョンみたいな感じ。

このfirewalldはいわゆる「パケットフィルタリング」というものをしてくれている。
パケットフィルタリングではサーバーに送られてきたパケットの送信先・元IPやポート番号でフィルタリングをする機能。

例えば、22番ポート(一般的にはSSH)のみを許可すると、それ以外のポートにリクエストを送ったパケットは全部ファイアウォールで拒否される。

また、自分のIPアドレスのみを許可するとそのIPアドレスでしかアクセスできなくなるみたいなこともできる。

とにかく、色々ネットワークの制限をかけられるのがファイアウォール。

firewalldを覗いてみる

firewalldにはゾーンという制限のかけ方がある。

現在のゾーンを

“sudo firewall-cmd –get-active-zone”

で確認。

これはつまり、「eth0という名前のネットワークインターフェースを通る通信はpublicというゾーンルールで処理されるよ」ということ。

ネットワークインターフェースについて説明したかったんだけど、ちょっと厄介なのでOSI参照モデルを説明するときに説明する。

このpublicというゾーンは以下のように定義されている。

見てみると、ssh、dhcpv6-client、cockpitというのが許可されている。
sshは分かると思うのでスルー。
dhcpv6-clientはDHCPというIPアドレスを自動割り当てするシステムのIPv6バージョン。
cockpitはサーバーを管理できるツールのことみたい。

どちらもちょっと消すのは怖いので、このままにしておく。

Apacheを入れて動作確認してみる

とりあえず、ここからもうComposer、PHP、Apache、Laravel、MySQL、Breezeを入れたら完成なのでは? と結構安易な発想。

前の私のブログを見返すとApacheから入れてるので同じくApacheから入れていこう。

今はfirewalldでpublicゾーン設定なので、Apacheを入れても直ぐ外部からサイトにアクセスは出来ないはず。
あと、firewalldの設定で特定のIPのみHTTPへの接続許可をすれば私のIPからしかアクセスできないみたいなのもできる。

“sudo dnf update”
でdnfパッケージをアップデートして
“sudo dnf install httpd”でApacheとその依存関係をダウンロード&インストール。
“sudo systemctl status httpd”で起動しているかを一応確認。起動はしてなかった。
“sudo systemctl start httpd”でApacheの起動をしてみる。

Apacheを起動すると共に80番ポートで通信が始まるけど、firewalldで制限してるので恐らく大丈夫。

一応、ここでグローバルIPアドレスを入れてアクセスできるかを確認。

タイムアウトになったので、恐らく問題なし。

次は、ファイアウォールで自分のIPだけHTTP接続を許可してみる。
方法はこちらを参考に。

今回の場合は、私のIPアドレスからHTTPのポートにアクセスがあった場合許可したいので

“sudo firewall-cmd –permanent –zone=public –add-rich-rule=’rule family=”ipv4″ source address=”xx.xxx.xxx.xxx” service name=”http” accept’”
のような感じに。permanentを付けないと永続しないので注意。

設定を変えたら

“sudo firewall-cmd –reload”
で設定の適用。

適用し次第、まずSSH接続を切らずに新しくSSH接続を試みる。

もし、SSH接続の設定が変更されちゃっていると、ここでクラウドにアクセスできないので、現在の接続を大切に復旧を試みる。

流石に心配しすぎかもしれないけど、一応ね。

私の場合は勿論問題なかったので、このままグローバルIPでアクセスしてみる。

よし! アクセスできた。

スマホからLTEでアクセスしてみる。

うん、他のIPアドレスからはアクセスできないのでヨシ!

PHPのインストール

Composerのインストール前に、そもそもPHPが必要なのでPHPのインストール。

“sudo dnf install php”
でPHPとその拡張モジュールのインストール。

Composerのインストール

Composerの公式ドキュメントにある方法でインストールする。

インストールし終わったら
“sudo mv composer.phar /usr/local/bin/composer”
でcomposer.pharを適切な位置へ。

次にcomposerのアップデートをしてみる。

“composer self-update”

アップデートできればパスが通せてる証拠。

Laravelのインストール

“composer global require laravel/installer”
でLaravelのインストール……をしようと思ったんだけど、新しくLaravelプロジェクトを作るわけではないので、今回は要らないみたい。

この”composer global require laravel/installer”っていうのはLaravelのインストーラー、つまりLaravelのプロジェクトを作成するときに使うインストーラーをダウンロードするだけなので、既にプロジェクトがあるならいらないんだね。

今回の場合はVMのLaravelプロジェクトをそのままクラウドのプロジェクトにコピーすればいい。

ここでgitを利用してもいいんだけど、gitだとgitignoreに入っているのは適用されないのでrsyncというSSHを利用したファイル転送コマンドを使う。

これは送信側だけでなく受信側でもrsyncを入れておく必要がある。

実際に打ったのはこんなコマンド
rsync -avz -e “ssh -i 【秘密鍵のパス】” /home/toppakou/QTM ユーザー名@xxx.xxx.xxx.xxx:【送信先パス】

-avzはそれぞれ、aがパーミッションの保持、vが処理中にその軌跡をコマンドラインに表示、zがデータ圧縮。

“ssh -i 【秘密鍵のパス】”というのはssh接続、つまりSSHで22番ポートを利用して接続するという設定。-iの次に秘密鍵のパスを指定。

この為に秘密鍵をteratermを使いVMに送信。使い終わったら削除している。

時間は意外と5分くらいかかった。

とりあえず、これでLaravelは完了?

MySQLのインストール

本当はサブネットマスクなどを利用してDBサーバーを隔離したりするんだけど、今回私の場合はそういうのが設定できないので普通にMySQLを入れてみる。

“sudo dnf install mysql-server”
でインストール。

“sudo systemctl start mysqld”
でmysqlの起動。

“sudo mysql_secure_installation”
でセキュリティ設定。

  1. rootパスワードは強力なものを
  2. Remove anonymous users? [Y/n]
    匿名ユーザーの削除。
    Y
  3. Disallow root login remotely? [Y/n]
    リモートでのログインを拒否するか。
    Y
    これは、SSHでクラウドにログインして、クラウドからMySQLに接続するので問題なし。
  4. Remove test database and access to it? [Y/n]
    テストデータベースの削除。
    Y
  5. Reload privilege tables now? [Y/n]
    設定の適用を今すぐするか。
    Y

ログインしてDBを作成してみよう。

“show databases;”でとりあえずdatabaseを見てみる。

まあそうだよね。

“create database DB名;”でDBの作成。

とりあえずこれでいいかな?

PHPやLaravelの本番用.env

設定ファイルを弄っていく。

php.ini

こちらを参考に以下のように設定。

date.timezone = "Asia/Tokyo"
mbstring.language = Japanese
mbstring.detect_order = UTF-8,SJIS,EUC-JP,JIS,ASCII 
upload_max_filesize = 10M
post_max_size = 10M

また、display errors = Offなのを確認

これがOnだと、エラー時にエラーログみたいなのがブラウザに表示されちゃう。

Laravelの.env

こちらも先ほどの記事を参考に設定。

あんまり見せられるのが無いんだけど、記事先の物とほぼ同じ。

config/database.php

こちらの

'connections' => [
  'mysql' => [
    'collation' => 'utf8mb4_bin',

の設定をしておいた。

Composer installの実行

“Composer install”をプロジェクト内で行うとComposer.jsonにあるパッケージをインストールしてくれる。

これでBreezeなどもインストールしてくれる。

migrateしてみる

色々設定をしたので、マイグレートしてみよう。

“php artisan migrate”
でマイグレート……する前に

“sudo dnf install php-pdo php-mysqlnd”
でドライバのインストール。

改めて
“php artisan migrate”

問題なさそう。

バーチャルホストの設定

現在、Apacheは/var/www/html以下がドキュメントルート、つまり読み込み可能領域となっている。

そこからさらにLaravelのpublicフォルダをApacheに読み込ませてあげたいんだけど、そもそもLaravelの位置が少し変なのでそこから修正する。

現在は私のユーザーディレクトリ直下にLaravelプロジェクトがあるんだけど、普通は/var/www/Laravelプロジェクトみたいな感じにするっぽい。

“sudo mv QTM /var/www/”
でQTM(Laraveプロジェクト)を移動。

次にバーチャルホストの設定。

sudo vim /etc/httpd/conf.d/qtm_app.conf

と指定し、バーチャルホストの設定。

<VirtualHost *:80>
  DocumentRoot /var/www/QTM/public
  <Directory /var/www/QTM/public>
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>

この<VirtualHost *:80>はドメイン名は何でもよいので、80番ポートを通過する場合に適用される設定。

AllowOverride AllはApacheが.htaccessを読み込む際に必要な設定。

Require all grantedはApacheの権限関係の許可をしている。

これで
“sudo systemctl restart httpd”
でリスタートしてみたけど……繋がらないね。

フォルダとかファイルの権限の問題っぽい。

Apacheへの参照権限

前回を見てみるとApacheを自分のユーザーグループに入れることで解決してたんだけど、それだとApacheの持つ権限が大きくなっちゃうので、今回は必要なところだけ権限を与える。

具体的にはLaravelプロジェクト/storageとLaravelプロジェクト/bootstrap/cacheにあるフォルダの所有者をApacheにして、それぞれ755権限にする。

恐らく、Laravelというグループを作ってそこに自分とApacheを入れる方法でも問題ないんだけど、今回はこれだけなので直接設定しちゃう。

“sudo chown -R apache:apache /var/www/QTM/storage”
“sudo chown -R apache:apache /var/www/QTM/bootstrap/cache”
“sudo chmod -R 755 /var/www/QTM/storage”
“sudo chmod -R 755 /var/www/QTM/bootstrap/cache”

755に設定しているので、所有者であるApacheだけが書き込みできる状況。

やってみたけどダメだった。

“sudo cat /var/log/httpd/error_log”でエラーログを見てみると、Permission deniedとの文字が。

フォルダは実行権限を指定しておかなきゃダメらしく、ちょっと怪しそうなので魔法のコードを。

“sudo find ./ -type d -exec chmod 755 {} \;”
“sudo find ./ -type f -exec chmod 644 {} \;”

このコードを説明すると、findが指定したディレクトリ以下の全てのフォルダ・ファイルを探索するコマンド。
今回は./と指定しているので、現在ディレクトリからそれ以下を探索する。
-type dはディレクトリのみ、-type fはファイルのみという意味。

-execはそれ以降に好きなコマンドを打つよという意味。
chmod 755の部分が好きなコマンド。
{}は変数みたいなもんで、{}の部分に該当するパス名が入る。
\;はコマンドの終了を意味する。

うん、ややこしいね。
つまり、上はディレクトリに対し755、所有者だけ全部、他は読み取りと実行を。
下はファイルに対し644、所有者だけ読み込みと書き込みを、他は読み取りを許可している。

なんかこの設定が定番らしい。

実行してみる。

うん、ダメだね。

SELinuxを止めてみる

どうやらSELinuxが拒否してるみたいなので、SELinuxを一時的に停止してみる。

恐らくそこまで、滅茶苦茶危険ってわけではないんだけど、あまり長くやりすぎるのも良く無さそうなので、本当に少しだけね。

“sudo setenforce 0”

で実行はするけど、記録だけして拒否はしないモードになる。

“sudo setenforce 1”で元に戻せるよ。

アクセス。

結果→500番エラーに変わった。

Apacheのエラーログを見る感じ、Viteがあーだこーだしてエラー吐いてるみたい。

Vite manifest not foundとある。
これ、Vite使ってるからCSSとかそういうのビルドしなきゃいけないのか。

色々調べて見た感じ、npm run devをするんじゃなく、npm run buildでビルドしちゃって、/public/build/のbuildフォルダをそのまま送っちゃうのがいいね。

VMで”npm run build”して、”rsync -avz -e “ssh -i 【秘密鍵のパス】” QTM/public/build/ 【ユーザー名】@xxx.xxx.xxx.xxx:xxx/xxx/QTM/public/build/”みたいな感じで転送。

……動くかな?

動いた!

おわりに

この1週間は自己学習だけでなくインターンや友達との旅行が重なって思うようにできなかった。
スケジューリング力は大事。
特に、インターンシップは自分に合った量が良い。取捨選択大切。

後、BBQは紙皿、紙コップがいい。割れるから。しかも2個も。

今は指定したIPからしかアクセスできないのでほぼローカル環境みたいなもんなんだけど、次はこの制限を取っ払って誰でもアクセスできるようにしたい。

でも、誰でもアクセスできるようにするとセキュリティがだいぶ心配なので、色々調べながらやる感じかなぁ。

おやすみなさい。