sorta kinda...

主にAWS関連ですが、これに限らずいろいろ勉強したことや思ったことを書いていきます。

EC2 インスタンスのセキュリティ評価をやってみよう

久々に AWS コンソールを触った気がします、那須です。

システムの運用をしていると、しょっちゅう出てくる脆弱性情報…なんとかしないとって思っていても、後手後手になったりしますよね(私だけですかね…? 対応はパッチ適用やカーネル更新が主なので、アプリへの影響を考えるとちょっと簡単にはできなかったり。 なかなか難しいですね。

かといって放置してると、↓このようにシステムに何か悪さをされたりします。。
f:id:nasrinjp1:20181009162109p:plainf:id:nasrinjp1:20181009162200p:plain

 

セキュリティ評価だけでも自動実行させよう

セキュリティ評価を RSS 等で情報を拾って対象システムや影響を考えて、、って感じで手作業でやってる人は多いと思います。 今は AWS から Inspector というサービスが出ていて、EC2 インスタンスを対象にセキュリティ評価をしてくれるものがありますので、こういうサービスを積極的に使っていきましょう! なるべく早く、しかも機械的に検知したいですね。

ちなみに、この記事を書いている時点で EC2 インスタンスWindows Server を対象にできるツールやサービスは他にもありますが、お手軽にできるという観点で Inspector を選びました。 Linux が対象であれば Vuls とかなんとかもありますので、選択肢はいろいろありますよ。

評価の結果、対応が必要となってもすぐに対応することは現実的には難しい場面はあると思います。 が、運用中のシステムが現在脆弱性を抱えているのかどうかを知っているのと知らないのでは状況が大きく異なります。 知っていればワークアラウンドでしのぐこともできますよね。 セキュリティ評価だけでも定期的に自動で実施できる環境にしておくと安心ですね。

Inspector のドキュメントもちゃんとそろってますので、これを頼りにセキュリティ評価をやってみましょう。
docs.aws.amazon.com

 

評価結果を見るまでの流れ

AWS コンソールからやってみたので、流れを追っていきましょう。

評価するターゲットを指定するため、「作成」を押しましょう。
f:id:nasrinjp1:20181009145948p:plain

評価ターゲットの名前を決めます。 「All Instances」にチェックを入れると、現在設定している AWS アカウントのリージョンのすべてのインスタンスが対象となります。
対象インスタンスを絞りたい場合は、タグで指定します。 この図は、inspector というタグの値が yes となっているインスタンスのみを評価対象とする例です。
「Install Agents」にチェックを入れると、対象インスタンスに Inspector 用のエージェントが Systems Manager の Run Command で自動インストールされます。
f:id:nasrinjp1:20181009150100p:plain

「保存」を押すとこんなメッセージが画面上部にでます。超意訳すると Run Command でエージェントインストールするように設定したから詳細は Run Command で確認してね!って感じです。
f:id:nasrinjp1:20181009150114p:plain

実際に Systems Manager の Run Command コンソールに移ると、AmazonInspector-ManageAWSAgent というドキュメントが実行されていることがわかります。
f:id:nasrinjp1:20181009150122p:plain

Run Command のログを見ると、最初に Iinux 用のエージェントをインストールしようとしてから、Windows 用のエージェントのインストールを行っています。今回の例では、すでに EC2 インスタンスにエージェントが入っているのでスキップされていますね。
f:id:nasrinjp1:20181009150132p:plain

Inspector エージェントが正常稼働しているかどうかは、Inspector コンソールの評価ターゲットの「Preview Target」を押すと確認できます。
f:id:nasrinjp1:20181009150143p:plain

Agent Status が「HEALTHY」になっていれば正常稼働していることになります。
f:id:nasrinjp1:20181009150153p:plain

評価ターゲットが決まれば、次に評価テンプレートを作成しましょう。
f:id:nasrinjp1:20181009150202p:plain

名前は評価テンプレートの名前です。
ターゲット名は先ほど作成した評価ターゲットの名前を選択します。
ルールパッケージというのは、実際に評価するポイントをまとめたものです。選択したルールパッケージを基にセキュリティ評価が実行されます。
所要時間はセキュリティ評価にかける時間です。長ければ長いほど正確な評価が行われます。
f:id:nasrinjp1:20181009150214p:plain

サポートOSごとに提供されるルールパッケージが異なりますので、事前に↓この対応表を確認しておいた方がいいでしょう。
docs.aws.amazon.com

評価実行後にイベントごとに SNS で通知したい場合は、ここで SNS トピックを指定します。
また、評価結果にユーザ属性をつけたい場合は、結果に追加された属性にキーと値を指定します。
Assessment Schedule にチェックを入れると、指定した日数ごとに評価が実行されます( 1 回だけ実行したい場合は、このようにチェックを外せば OK です
「作成および実行」を押すと、初回の評価が行われます。
f:id:nasrinjp1:20181009150228p:plain

評価中はこのように「データを収集中」という状態になります。
f:id:nasrinjp1:20181009150241p:plain

評価の実行コンソールでも、「データを収集中」になっていますね。
f:id:nasrinjp1:20181009150257p:plain

ステータスだけだとよくわからないですが、実行中の評価を展開して「ステータスを表示」を押すと今の状態が分かります。
f:id:nasrinjp1:20181009150305p:plain

12 分間評価していて、4404 メッセージを 1 つのエージェントから受信していることが分かりますね。
f:id:nasrinjp1:20181009150313p:plain

Telemetry という単語が出てきていますが、これは次世代のモニタリングの仕組み?のようです。↓こんな記事がありました。
SNMPの課題とTelemetry登場の背景 | ビジネスネットワーク.jp

評価が終わるとステータスが「分析完了」となります。一番右側に Reports 欄があって、そこからこの評価実行についてのレポートがダウンロードできます。
f:id:nasrinjp1:20181009150322p:plain

フォーマットは、HTML か PDF ですね。
f:id:nasrinjp1:20181009150331p:plain

PDF で作成してみました。全部英語ですが、脆弱性の情報だとどの CVE にひっかかったのかが分かります。
f:id:nasrinjp1:20181009150343p:plain

結果のページではひっかかった情報が一覧で表示され、それぞれ展開することで詳細な情報を確認できます。
この例だと IE 関連の脆弱性にひっかかっていますね。
f:id:nasrinjp1:20181009150353p:plain

結果をフィルタすることもできます。この例だと、重要度を Medium、テキストで「sql server」でひっかかるものだけを表示しています。
これである程度製品ごとに状況を確認できますね。
f:id:nasrinjp1:20181009150406p:plain

ちなみに、イベントごとに SNS で通知するよう設定していると、このような JSON 形式で内容が通知されていました。

{
    "template": "arn:aws:inspector:ap-northeast-1:xxxxxxxxxxxx:target/0-dxX9mKxw/template/0-KBmzcUXo",
    "run": "arn:aws:inspector:ap-northeast-1:xxxxxxxxxxxx:target/0-dxX9mKxw/template/0-KBmzcUXo/run/0-RKbS95pt",
    "time": "2018-10-08T23:49:29.765Z",
    "finding": "arn:aws:inspector:ap-northeast-1:xxxxxxxxxxxx:target/0-dxX9mKxw/template/0-KBmzcUXo/run/0-RKbS95pt/finding/0-O5Bd010v",
    "event": "FINDING_REPORTED",
    "target": "arn:aws:inspector:ap-northeast-1:xxxxxxxxxxxx:target/0-dxX9mKxw"
}

これだとなんのこっちゃ分かりませんが、finding ARN から describe-findings で詳細を取れるので、SNS の内容を基にさらに CLI 等で詳細をとってきて人が見てわかる内容でインシデント登録する、といったシナリオも作れそうですね。
describe-findings — AWS CLI 1.16.29 Command Reference

 

セキュリティを意識してみよう

L3/L4 のレイヤでセキュリティ対策している人は多いと思いますが、脆弱性については導入当時は考えたけど運用に入ってからあまり意識してチェックしてないって方ももしかしたらいるんじゃないでしょうか?
Inspector やそれに代わるツールやサービスはたくさんありますので、今運用中のシステムのセキュリティについてもう一度考えてみましょう(自戒の念をこめて。。

Secrets Manager を使ってスクリプト内に秘密情報を書かないようにしよう

スクリプトを書いてるとあっという間に時間が過ぎます、那須です。

先日、Datadog から Slack と Backlog に障害通知する記事を書きました。今日の記事は↓の続編になりますので、まだ読んでない方は先に読んだ方が全体の流れはわかると思います。
nasrinjp1.hatenablog.com

Lambda の Python スクリプトに直接 apikey などの情報を書いてしまっていたので、スクリプトの汎用性を高めると同時にセキュリティ的に github にあげても問題ない内容に更新しました。今回はその変更点についてです。

 

変更したポイント

  • apiKey、projectId、issueTypeId の値を Secrets Manager から取得する流れにした
  • API Gateway の URL と Secrets Manager で作成したシークレット名は Datadog Webhooks に仕込んだ

 

Secrets Manager への値の登録

post_on_backlog というシークレットを作成して、そこに apiKey、projectId、issueTypeId の 3 つの値を登録します。
f:id:nasrinjp1:20180907062727p:plain

Secrets Manager へのシークレットの登録の流れは、この記事で書いていますので参考にしてください。
nasrinjp1.hatenablog.com

 

Lambda function の変更

↓書き直したスクリプトです。ざっくりですがコメントいれてます。

# coding: utf-8
import json
import requests
import boto3
from botocore.exceptions import ClientError

def lambda_handler(event, context):
    title = event['title']
    description = event['body']
    secret_name = event['secret_name']  # Datadog から値を取得する流れに
    url = event['url']  # Datadog から値を取得する流れに
    if event['alert_type'] == 'warning':
        severity = 3
    else:
        severity = 2
    return add_issue(title, description, severity, secret_name, url)

def add_issue(title,description,severity,secret_name,url):
    secret_info = get_secret(secret_name)  # ここにあった秘密の情報は Secrets Manager から JSON で取得する流れに
    payload={
        "apiKey"      : secret_info['apikey'],  # 取得した JSON から値を取り出す
        "projectId"   : secret_info['project_id'],  # 取得した JSON から値を取り出す
        "issueTypeId" : secret_info['issuetype_id'],  # 取得した JSON から値を取り出す
        "priorityId"  : severity,
        "summary"     : title,
        "description" : description,
    }
    response = requests.post(url, params=payload)
    return response.json()

# Secrets Manager から値をとってくる関数を追加(Secrets Manager コンソールのサンプルほぼそのまま)
def get_secret(secret_name):
    endpoint_url = "https://secretsmanager.ap-northeast-1.amazonaws.com"
    region_name = "ap-northeast-1"

    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name,
        endpoint_url=endpoint_url
    )

    try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
    except ClientError as e:
        if e.response['Error']['Code'] == 'ResourceNotFoundException':
            print("The requested secret " + secret_name + " was not found")
        elif e.response['Error']['Code'] == 'InvalidRequestException':
            print("The request was invalid due to:", e)
        elif e.response['Error']['Code'] == 'InvalidParameterException':
            print("The request had invalid params:", e)
    else:
        secret_value = json.loads(get_secret_value_response['SecretString'])
        return secret_value

あと、Secrets Manager から値を取得するための IAM ポリシーが必要になるので、Lambda function にアタッチしている IAM ロールに下記のアクションを許可するようにポリシー追加します。* を使わない方がいいとは思いますが、ひとまずこれで。kms:Decrypt アクションは、KMS でデフォルトのものではなく CMK を使ってシークレット情報を暗号化している場合は必要になります。
docs.aws.amazon.com

{
            "Effect": "Allow",
            "Action": [
                "secretsmanager:Describe*",
                "secretsmanager:Get*",
                "secretsmanager:List*",
                "kms:Decrypt"
            ],
            "Resource": "*"
        }

 

Datadog webhooks 設定で API Gateway に投げる情報を追加

Custom Payload に secret_name と url の情報を追加します。
f:id:nasrinjp1:20180907063827p:plain

 

テストしてみよう

上記のように変更して動作テストをしてみます。今回は alert_type を warning で検知したものを backlog に優先度「中」で登録できるかも一緒に確認しましょう。

対象の EC2 インスタンスに負荷をかけていくと Warning で CPU 負荷異常を検知しました。
f:id:nasrinjp1:20180907064749p:plain

と同時に Backlog にも課題登録され、優先度は中で登録されていました。Lambda の severity 指定部分の処理も ok ですね。 f:id:nasrinjp1:20180907064758p:plain

 

まとめ

これでスクリプトgithub 等で公開しても大丈夫な状態になりましたね。IAM ポリシーとかをもうちょっと調整したら公開しようと思います。