私の戦闘力は53万です

awsとgcpについて書きます

AWS WAF 海外IPを拒否しGoogleのクローラ(bot)は許可する設定

AWS WAF 海外IPを拒否しGoogleのクローラ(bot)は許可する設定」を
することがありましたので設定時のメモとして書きます。
 

Googleのクローラの条件

まずは通すべき条件を調べました。
色々と細かい条件はあるようです。今回の私の要件は
User-Agentヘッダに「Googlebot」が含まれていれば
Googleのクローラとして見なしてOKだったので
そちらをGoogleクローラの条件としました。
 

海外IPアクセスの条件

AWS WAFはIPを国別で判断して許可・拒否することが可能です。
こちらはデフォルトの機能を利用します。

AWS WAFを設定 

 まず1つ目のCondition作成として「string and regex match」を選択します

f:id:remmemento:20191130144740p:plain



「Googlebot」をuser-agentヘッダに含む場合の条件を作成します。

f:id:remmemento:20191130144036p:plain

 

 

f:id:remmemento:20191130144230p:plain

上記のように入力しAdd filterボタンを押します。

 

 

 

f:id:remmemento:20191130144241p:plain

Filterに追加されたらCreateボタンを押します。

 

 

 

条件作成2個目

2つ目の条件は国別の制限をします。Geo matchを選択します。

f:id:remmemento:20191130144918p:plain

 

日本を登録します 

f:id:remmemento:20191130145158p:plain

ルール作成

上記で作成した条件を元にルールを作成します

f:id:remmemento:20191130145316p:plain

 

上記で作成した条件を設定します。

この時、WAFのデフォルトルールを

Allowにしたかったので下記のようにルールを設定しています。

f:id:remmemento:20191130143352p:plain

上記の意味が少し分かりにくいと思いますので掘り下げます。

条件の整理

私は条件の組合せを考えるときは
頭の中が混乱するので、極力ド・モルガンの法則をベースに考えています。
もっと良い方法があれば知りたいのですが、
こんな方法あるよ!という方いたらぜひコメントください。
 
 
例えば下記のように考えます。
A=「User-agentにGooglebotを含む」
B=「日本からのアクセス」
上記のルールはを意味します。
 
=「User-agentにGooglebotを含まない」かつ「日本からのアクセスでない」
=「User-agentにGooglebotを含まない」かつ「海外アクセスである」
となります。 
 
デフォルトの設定がAllow/Denyにより設定内容が異なるのですが、
今回はデフォルトをAllow(許可)にしています。
 
上記設定は下記のように動作します。
  • 「User-agentにGooglebotを含まない」かつ「海外アクセスである」場合ブロック
  • それ以外はAllow(許可)

 ド・モルガン風に考える

Blockの挙動を否定と置き換えて考えると
の否定(Block)なので、
ド・モルガンの法則の両辺を否定してみます。
すると、f:id:remmemento:20191130150433p:plainの否定はとイコールであることが導かれます。
は「User-agentにGooglebotを含む」または「日本からのアクセス」
許可するを意味していますので、意図した設定であることが分かります。

検証してみる

上記で設定したWAFを適当なCloudFrontに設定してアクセス確認してみます。
#国内IP(xx.xx.xx.xx)からかつuser-agentにGooglebotが含まれないアクセス → アクセス成功
<!DOCTYPE html>
<html lang="ja">
・・・・・・・・・・・・
#国内IP(xx.xx.xx.xx)からかつuser-agentにGooglebotが含まれるアクセス → アクセス成功
<!DOCTYPE html>
<html lang="ja">
・・・・・・・・・・・・
 
 
#whois yy.yy.yy.yy |grep City
City:           Seattle
City:           Singapore
 
#海外IP(yy.yy.yy.yy)からかつuser-agentにGooglebotが含まないアクセス → アクセス失敗
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>403 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Request blocked.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: OLTvH3ay52g-1i32HRmRi-XBxlGINEvGdBF5HGgUHt14Qe62zYIb6A==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>
 
 
#海外IP(yy.yy.yy.yy)からかつuser-agentにGooglebotが含まれるアクセス → アクセス成功
<!DOCTYPE html>
<html lang="ja">
・・・・・・・・・・・・
 上記から、
「海外IP(yy.yy.yy.yy)から」かつ「user-agentにGooglebotが含まない」アクセスのみが
拒否されていることが確認できました。

注意点

User-Agentのヘッダは上記の検証で実施しているように
なりすましが可能です。
そのため、より厳密に設定したい場合は、
例えば下記のような設定が追加で必要になってくるのかと思いました。
 
  1. WAFログを定期的に解析しアクセス元IPをDNSリバースルックアップ[※1]を実施
  2. なりすましのアクセス元IPを判定する
  3. 2のIPをWAFのIP拒否リストに設定する
[※1]
 
機会があれば試してみたいと思います!
 

AWS KMS の概要とエンベロープ暗号化について説明してみる

最近AWS KMSについて聞かれることがあったので

ブログにまとめてみようと思います。 

KMSってなに?をざっくり

  • 対象鍵を安全に保管してくれるサービス
  • AWSサービスのデータ暗号化・複合化する機能として連携(S3、EBS等)
  • うるさいセキュリティのポイントをある程度抑えてくれる(キーローテーション、暗号化鍵の方式を決定)
 
記事執筆時点で非対称の鍵もサポートが開始されたようです。
まだ内容がわからないので今回は対象鍵の部分について書きます! 

前提知識:対称鍵とは

対称鍵というのは暗号化と復号化の時の鍵が同じことを指します。
身近な例では、ファイルをzip暗号化でパスワードを利用するケースです。
暗号化する時と、復号化する時で同じ鍵(パスワード)を指定しますね。
もっと身近な例だと家の鍵です。
鍵をしめる(暗号化)時と、鍵を開ける(複合化)するときで
同じ家の鍵を使いますね。
 

キーの種類

1つ目の混乱ポイントです。
KMSでは鍵の種類がたくさん出てきます。
私は初見に結構混乱しました。
鍵の全体像を整理すると下記のようになります。
kms/
├── cmk
│   ├── AWS所有
│   ├── AWS管理
│   └── カスタマー管理
│       ├── aws_make
│       └── origin_external
└── データキー

下記に簡単な説明を書きます。

AWS所有

  見ることすらできない鍵です。AWSが利用します。

  基本的に触れないので理解すべきこともないです。

AWS管理

 もっともよく使う鍵です。

 おおよそのケースで単純に暗号化したいだけならこの鍵を利用します。

    デフォルトの鍵です。aws/service-nameの形式で存在します

 ある程度AWSが用意した枠組みでしか管理ができないため

 細かい制御が必要な場合は後述のカスタマー管理のキーを利用します。

 例えば、クロスアカウントで共有が不可のため、

 複数アカウントが関連するときは利用できないケースが多いです

・カスタマー管理

 AWSで作れる鍵です。この鍵だとキーポリシー(アクセス制限)とか、
 手動のキーローテーションとか、有効無効の操作の自由度が高くなります。
 また、クロスアカウントでの利用にもこちらを用いることが多いです。
 カスタマー管理キーは2種類に分かれます。
 インポートされたキーマテリアル(origin external)と
 awsで作成する鍵(aws make)です。
 基本的にはawsで作成する鍵を利用しますが、
 暗号化方式まで厳密に管理したい、
 自分たちで自作した鍵を利用したいという場合には
 インポートされたキーマテリアル(origin external)を利用します。

・データキー

CMKを元に作成するキーのことです。
データキーがなぜ必要なのか?と思う人もいると思います。
これに対する答えとしてまず、
エンベロープ暗号化の概念を理解する必要があります。
 
AWS KMSで管理するキー(CMK)では暗号化の対象データ容量の上限が
32KB(記事執筆時点)とかなり小さいです。
例えばこの制限で、容量の小さいデータを暗号化するのであれば良いのですが、
基本的にはEBSやS3内のファイルも32KBを上回ることが想定されるため
管理ができません。
 
そこで、下記例に習いファイル容量に依存しない暗号化管理を実現します。
この考え方がエンベロープ暗号化です。
(1)CMK(MasterKey)からDataKeyを作成する。
(2)Datakeyを鍵として32KBよりも大きいデータ(EBS等)を暗号/複合化する
通常の運用では、このデータキーは利用時にはPlaintext(複合化された状態)で利用し、
利用が終わったら捨てます。そして暗号化されたDatakeyは取っておきます。

上記のように運用することで下記を実現できます

・容量大データも一律して同じ大きさのDatakeyを利用し暗号/複合管理

・外部に漏れるとマズイ情報(Plaintext data key)は必要な時のみ取出し利用 

https://docs.aws.amazon.com/ja_jp/kms/latest/developerguide/concepts.html#enveloping

KMSのAPIにも、キーを生成するAPIが2つあります。

kms:CreateKey
kms:GenerateDataKey
 
上記は考え方ですので、実際にCLIを使って動作させてみます。
一度実行してみると頭の中で理解しやすいのでおすすめです。

エンベロープ暗号化をCLIで一通りこなしてみる

まずはKMSを生成します

f:id:remmemento:20191127100736p:plain

create-key
aws kms create-key
{
   "KeyMetadata": {
       "AWSAccountId": "xxxxxxxxxxxx",
       "KeyId": "08e5af4f-ba9c-4f97-b6ec-xxxxxxxxx",
       "Arn": "arn:aws:kms:ap-northeast-1:xxxxxxxxxxxx:key/08e5af4f-ba9c-4f97-b6ec-2425af102c37",
       "CreationDate": 1574814784.429,
       "Enabled": true,
       "Description": "",
       "KeyUsage": "ENCRYPT_DECRYPT",
       "KeyState": "Enabled",
       "Origin": "AWS_KMS",
       "KeyManager": "CUSTOMER"
   }
}
 
キーIDだと分かりにくいので、名前(エイリアス)をつけてあげます 
aws kms create-alias --alias-name alias/test-key-alias --target-key-id 08e5af4f-ba9c-4f97-b6ec-xxxxxxxxx
 
続いてCMKからデータキーを作成します。
 

f:id:remmemento:20191127100812p:plain

data-key
 
 
aws kms generate-data-key --key-id alias/test-key-alias  --key-spec AES_256
{
   "CiphertextBlob": "AQIDAHgUOG52kcVFzz8bdP3olHhXcKqCGSU2gEsFuwNubXG8cwFCIZXzwNgvlmH5UznwhMFTAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMck1KFok17ktpT6jkAgEQgDu+39yXM9ajyk3YiIWbeiqaHnxDRqR8Jfl8BZedHyjpy+v4BK4FlIMSuEc0Xmpkjuau8M7qNu4Yim2ndQ==",
   "Plaintext": "KWDD1Gs6L7qQFllFexj8PmbHEpjxABVsvZ7sGv40ENc=",
   "KeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxx:key/08e5af4f-ba9c-4f97-b6ec-xxxxxxxx"
}
 
「CiphertextBlob」は「Plaintext」を暗号化した情報のことです。「CiphertextBlob」を利用して複合化してみましょう。
 
aws kms decrypt --ciphertext-blob fileb://<(echo 'AQIDAHgUOG52kcVFzz8bdP3olHhXcKqCGSU2gEsFuwNubXG8cwFCIZXzwNgvlmH5UznwhMFTAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMck1KFok17ktpT6jkAgEQgDu+39yXM9ajyk3YiIWbeiqaHnxDRqR8Jfl8BZedHyjpy+v4BK4FlIMSuEc0Xmpkjuau8M7qNu4Yim2ndQ=='|base64 -D)
{
    "KeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxx:key/08e5af4f-ba9c-4f97-b6ec-xxxxxxxx",
    "Plaintext": "KWDD1Gs6L7qQFllFexj8PmbHEpjxABVsvZ7sGv40ENc="
}
上記のPlaintext」と一致することがわかりますね。 さて、このデータキーの「Plaintext」を利用してさらにデータを暗号化します。

f:id:remmemento:20191127101005p:plain

データの暗号化
上記の例だとデータキーは「KWDD1Gs6L7qQFllFexj8PmbHEpjxABVsvZ7sGv40ENc=」です。
例えばzipとかの暗号化パスワードに利用するイメージです。
AWSサービスで利用した場合だとEBSやS3のデータの暗号化時に
上記の「Plaintext」部分が利用されます。
 データの暗号化が終わったら Plaintext(複合化された素の状態)の
キー情報は捨てます。Plaintextが外部に漏洩するとデータを
複合化される可能性があるためセキュリティ事故になってしまいます。

f:id:remmemento:20191127100716p:plain

データキーの管理
一方暗号化されたキーは(ローカルとかに)保存しておきます。
この暗号化されたキーは仮に外部に漏洩したとしても、CMKを利用できない限りは、データを複合化されることがないため実被害はありません。
(とはいえ漏洩しないに越したことはないです) 
その後は暗号化されたキー(CiphertextBlob)を保管しておき、
またデータの暗号化/複合化をしたい時には上記で実施したように
一時的にデータキーを複合化(Palintextを取出)して利用します。
aws kms decrypt --ciphertext-blob fileb://<(echo 'AQIDAHgUOG52kcVFzz8bdP3olHhXcKqCGSU2gEsFuwNubXG8cwFCIZXzwNgvlmH5UznwhMFTAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMck1KFok17ktpT6jkAgEQgDu+39yXM9ajyk3YiIWbeiqaHnxDRqR8Jfl8BZedHyjpy+v4BK4FlIMSuEc0Xmpkjuau8M7qNu4Yim2ndQ=='|base64 -D)
{
    "KeyId": "arn:aws:kms:ap-northeast-1:xxxxxxxx:key/08e5af4f-ba9c-4f97-b6ec-xxxxxxxx",
    "Plaintext": "KWDD1Gs6L7qQFllFexj8PmbHEpjxABVsvZ7sGv40ENc="
}
 
以上がデータの管理の流れとなります。
 
下記ポイントが抑えられていることが確認できたと思います。
・容量大データも一律して同じ大きさのDatakeyを利用し暗号/複合管理
・外部に漏れるとマズイ情報(Plaintext data key)は必要な時のみ取出し利用  

 

長くなってしまうので、残りの機能はまた次回以降で書きたいと思います。
 

AWS S3のオブジェクトを時間指定でパブリック公開する

S3のホスティングを利用している場合で、
オブジェクトを特定時間に公開したいと思うことがありました。
その際、S3のバケットポリシーを利用して公開時間を
設定することが可能でしたので備忘で記事にします。

検証内容

バケットポリシーの時間を更新する
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<bucket_name>/*",
            "Condition": {
                "DateGreaterThan": {
                    "aws:CurrentTime": "2019-10-24T03:00:00Z"
                },
                "DateLessThan": {
                    "aws:CurrentTime": "2019-10-30T15:00:00Z"
                }
            }
        }
    ]
}
 
上記で許可指定した時間内はアクセスが可能なことを確認
date --utc
2019年 10月 24日 木曜日 03:41:37 UTC
 
<!doctype html>
<html class="no-js" lang="">
<head>
  <meta charset="utf-8">
  ....................
  
バケットポリシーの時間を許可外の時間となるよう変更する
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<bucket_name>/*",
            "Condition": {
                "DateGreaterThan": {
                    "aws:CurrentTime": "2019-10-24T04:00:00Z"
                },
                "DateLessThan": {
                    "aws:CurrentTime": "2019-10-30T15:00:00Z"
                }
            }
        }
    ]
}
 
時間外はアクセスが拒否されることを確認
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>8CBC499D293CCE35</RequestId><HostId>yDbZevag/0yexwkf1FZZEsSNrGeh2d0fQFtxnG1dOINeEafDSAWOdgi9CypUybOlJA2ezhNjmMo=</HostId></Error>[ec2-user@ip-192-168-0-212 ~]$
 
誰かの参考になれば幸いです。
 
 

AWS:VPCピアリングでうまく接続できない時に確認したいこと

VPCピアリングでうまく接続できない時に確認したいことを、自分でもたまに忘れそうなのでメモがてら書きます。

セキュリティグループ、ルートテーブル、NACL

 この辺りは当然ですね。丁寧に確認しましょう。

OSポート許可(iptables,firewall等)

 windowsの場合だとパーソナルファイアウォールを一時的に無効化すると手っ取り早いです。

名前解決ができるかどうか

 RDS等の接続ができない場合は、こちらが怪しいです。
https://docs.aws.amazon.com/ja_jp/vpc/latest/peering/modify-peering-connections.html#vpc-peering-dns

GCP:限定公開アクセスとは何なのか試してみる

限定公開アクセス の機能概要

GCPのリソースへアクセスする際、
VPC内部のリソース(GCEとか)がインターネット回線でなく、
Googleの内部ネットワークを通じてアクセスできる機能のことです。
(下記図の吹き出し部分のイメージです)
 
AWSの人に向けて言うと、AWSVPCエンドポイント的なことです。
 
 
 

アクセスパターン

上記の図でSubnet2のGCEの各種条件を変えて、
それぞれのアクセスの可/不可を試してみました。 
No 条件1 条件2 条件3 外部アクセス
(yahoo.co.jp等)
GCP API へのアクセス GCP APIへの
private access
1 internetルート
(to 0.0.0.0/0)有
GCEへ外部IP付与有 限定公開アクセス有効 可能とのこと
googleの人へ確認)
2 internetルート
(to 0.0.0.0/0)有
GCEへ外部IP付与有 限定公開アクセス無効 不可
3 internetルート
(to 0.0.0.0/0)有
GCEへ外部IP付与無 限定公開アクセス有効 不可
4 internetルート
(to 0.0.0.0/0)有
GCEへ外部IP付与無 限定公開アクセス無効 不可 不可 不可
5 internetルート
(to 0.0.0.0/0)無
GCEへ外部IP付与有 限定公開アクセス有効 不可 不可 不可
6 internetルート
(to 0.0.0.0/0)無
GCEへ外部IP付与有 限定公開アクセス無効 不可 不可 不可
7 internetルート
(to 0.0.0.0/0)無
GCEへ外部IP付与無 限定公開アクセス有効 不可 不可 不可
8 internetルート
(to 0.0.0.0/0)無
GCEへ外部IP付与無 限定公開アクセス無効 不可 不可 不可
 
注意点はインターネットアウトのルーティングがない状態では限定公開アクセスが通用しないことです。
限定公開の Google アクセスを使用すると、内部(プライベート)IP アドレスしか持たない(外部 IP アドレスを持たない)VM インスタンスが、Google API とサービスのパブリック IP アドレスにアクセスできます。限定公開の Google アクセスは、サブネット レベルで有効にします。そうすると、サブネット内でプライベート IP アドレスしか持たないインスタンスが、デフォルト ルート(0.0.0.0/0)を通じて Google API とサービスにトラフィックを送信できるようになります。このとき、デフォルト インターネット ゲートウェイへのネクストホップを使用します
 

結論

上記の結果から 、ONにすると、GCPへのアクセスをセキュアかつ早く実現してくれるため基本ONにしておくのが良さそうです。
 
 

AWS SESとSPFの話(その2)

では、前回の続きです。

AWS SESでメールを送った時はどうなるのか?


まず、特に何も特別な設定はしないで、SESでメールを送ってみます。

受信者でgmailで受信した場合、
メッセージのソースを表示すると、詳細の情報が確認できます

f:id:remmemento:20191105204646p:plain
gmail

f:id:remmemento:20191105204723p:plain
上記からSPFの認証を合格(PASS)したことが確認できます。

ソースを確認

メールのソース部分を見ていきます。
SPFで検証するレコードは、下記になります
Return-Path: xxxxx-xxxxxx-xxxxxxx-xxxxxxx@amazonses.com

ここで、「あれ?amazonses.comからなんてメール送信していないのに?」と思うかもしれません。
実はAWS SESで送信するメールは、特別な設定をしない限りは「amazonses.com」から送信されます。

メール送信元の情報

ここが紛らわしいところです。
実はメールには、送信元の情報が2つ存在します。
1つはメールヘッダで、もう1つはエンベロープfromです。
呼び方は、いろんな呼ばれ方がありますが、要は2つあります。
代表的な用途としては、
メールヘッダの方は、メールアプリとかで送信元を表示するために、
エンベロープfromの方は、実際にメールが送信されるサーバを示すために利用されます。

なんでそもそも2個あるのかという説明は下記が分かりやすいかと思います。
https://business.biglobe.ne.jp/mail/semi/semi_002.html

SPFの確認をしてみる

SPFは実際にメールを送るサーバを検証したいので、エンベロープfromを検証します。
エンベロープfromはメールソースの「Return-Path:」を確認すれば分かります。

AWS SES でデフォルト設定で送信した場合、
SPFで検証するレコードは下記のようになっているはずです。
Return-Path: xxxxx-xxxxxx-xxxxxxx-xxxxxxx@amazonses.com

では「amazonses.com」のSPF設定(TXTレコード)を確認しましょう。

digします。

dig email.amazonses.com txt
amazonses.com. 117 IN TXT "v=spf1 ip4:199.255.192.0/22 ip4:199.127.232.0/22 ip4:54.240.0.0/18 -all"


SPFでは上記送信元IP(54.240.8.42)が送信元のIPと記載されています。
送信元のIP(54.240.8.42)が上記TXTレコードの
「ip4:54.240.0.0/18」部分に該当するしたため、SPF認証をパスしていることが分かります。

よってAWS SESでは、特に何も初期設定をしなくてもSPFの認証を通ってしまいます。
AWSのドキュメントにもそのことが記載されていますね。
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/spf.html

国内ケータイキャリアに送る時は対策が必要

ただ、これにプラスして、SESでは国内キャリアに送る場合、
特別な設定を追加しておいたほうが良いです。

au,docomoにおいて、迷惑メール設定次第では
senderID(上記で言うメールヘッダ)でのSPFレコード検査も実施される仕様のようです。
SPFレコードを設定することでメール到着率が上がることが報告されています。
下記が各会社のアナウンスです。
https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/spf.html
https://www.au.com/mobile/service/attention/spf-record/
https://www.nttdocomo.co.jp/service/imode_mail/notice/sender_id/

具体的にはTXTレコードに「v=spf1 include:amazonses.com」を追加する形となります。
digコマンドで引いた時に下記のように出てくるイメージです。
your_domainの部分は対象のドメインに置き換えてください。

your_domain TXT "v=spf1 include:amazonses.com ~all"

すでにTXTレコードが存在している場合はケースバイケースです。
SPFの書き方として下記が参考になると思います。
間違いから学ぶSPFレコードの正しい書き方 : 迷惑メール対策委員会

AWS SESとSPFの話(その1)

会社の人から「SPF認証ってなに?」とか
AWS SESはSPFに対応していますか?」といったことをよく聞かれます。
そこで今回はSPFについて書きたいと思います。

SPFとは

そもそもSPFとは何か?ということですが、
送信元認証(=メール送信者が想定と正しいと確認すること)の
技術の1つだと思ってもらえればと思います。

例えば、私がメールを送るとします。
私のメールアドレスは「xxx@hatena.com」とします。
しかし悪い奴が、私の名前を語り、悪いメールを出すとします。
fromのメールアドレスを「xxx@hatena.com」に偽ったとしましょう。

f:id:remmemento:20191105204119p:plain
1.sendmail
こんなことをされたら、私は迷惑です。
悪い奴が、私を装って悪意あるメールを送れてしまうからです。
上記のような悪意ある行為に対し「hatena.com」ドメインからの
メールはちゃんとした人からだけ送れるようにしたい!と思ったとします。
そこで、SPFの登場です。
設定により上記のような一部の悪意ある行動を防ぐことができます。

実際の設定例

SPFの設定例として、せっかくなので実物設定を見て見ましょう。
IT企業の富士通さんのSPF設定です。
例として使いやすいのでピックアップさせて頂きました。

SPFの設定は公開されています。
txtレコードをdigすると見ることができます。(執筆時点の情報です)
Maclinuxをお使いの方は、下記コマンドを実施して見てください。

dig fujitsu.com txt
fujitsu.com. 4502 IN TXT "v=spf1 ip4:211.128.242.0/26 ip4:202.219.69.128/26 include:spf.protection.outlook.com include:mktomail.com mx:fujitsu.com?all"


例えば、上記例の最初の部分「v=spf1 ip4:211.128.242.0/26」では、
IPが「211.128.242.0/26」のメールサーバから送られて来たら「fujitsu.com」からの本物のメールだとみなして良いよ
ということを表わしています。
※その他「ip4:202.219.69.128/26〜」以降の情報も同じように
spfのルールに従い処理されますが説明を分かりやすくするため割愛しています。

f:id:remmemento:20191105204208p:plain
2.fujitsu-example
このように「fujitsu.com」のドメイン管理者が、
fujitsu.com」のメールとして正しい条件を予め設定しておくことにより、
悪い奴がメールのfrom部分を「fujitsu.com」に偽造しようが、
受信者側で、本物か偽物かを見抜くことが可能になります。

このことを応用して、よくあるパターンとしては、
社内からのメールなのに、社外メールサーバからメールが来ていることを検知できます。
送信元メールアドレスを不正に社内用に書き換えることで社内の人間を装っても、社外から悪いメールを出しているためです。
(送信元メールアドレスを社内に書き換えても社外メールサーバのIPから送られてくるためSPFにより嘘がバレる)
流行りのなりすましメールの検出等もできますね。

では、AWS SESからの送信メールのSPFはどう処理されるのでしょうか?
続きは次回で見て見たいと思います。