共有アクセス署名(SAS)を使用することで、クライアントに付与するアクセスの種類を制御できます。 SASで以下のコントロールを設定できます:
- SAS が有効な間隔 (開始時刻と有効期限を含む)。
- SAS によって付与されるアクセス許可。 例えば、Event Hubsの名前空間のSASはイベントの受信許可を与えても、イベント送信の許可は与えない場合があります。
SAS認証は以下の利点を提供します:
- 有効な資格情報を提示するクライアントだけが Event Hub にデータを送信できる。
- クライアントが別のクライアントを偽装できないようにする。
- 不正なクライアントがイベントハブにデータを送信するのをブロックできます。
この記事では、SASを使ったEvent Hubsリソースへのアクセス認証について説明しています。 SASを使ってイベントハブリソースへのアクセス を認証 する方法については、「 共有アクセス署名を使ったイベントハブリソースへのアクセスを認可する」をご覧ください。
Note
セキュリティのベストプラクティスとして、共有アクセス署名ではなく、可能な限りMicrosoft Entraの認証情報を使用してください。共有アクセス署名はより簡単に侵害されやすいです。 引き続き Shared Access Signature (SAS) を使用して Event Hubs リソースへのきめ細かいアクセス許可を付与することはできますが、Microsoft Entra ID では同様の機能が提供され、SAS トークンを管理したり、侵害された SAS の取り消しを心配したりする必要がありません。
Azure Event Hubs での Microsoft Entra 統合の詳細については、「Authorize access to Event Hubs using Microsoft Entra ID」 (Microsoft Entra ID を使用した Event Hubs リソースへのアクセスを承認する) を参照してください。
SAS認証の設定
Event Hubs 名前空間またはエンティティ (イベント ハブまたは Kafka トピック) で、SAS 規則を構成できます。 消費者グループでSASルールを設定することはサポートされていませんが、名前空間やエンティティで設定されたルールを使って消費者グループへのアクセスを安全にできます。 次の図は、サンプル エンティティで承認規則がどのように適用されるかを示しています。
この例では、サンプルの Event Hubs 名前空間 (ExampleNamespace) に eh1 と Topic topic1 の 2 つのエンティティがあります。 承認規則は、エンティティ レベルと名前空間レベルの両方で定義されます。
manageRuleNS、sendRuleNS、listenRuleNS の認可規則は、eh1 と topic1 の両方に適用されます。 listenRule-eh および sendRule-eh の承認規則は eh1 にのみ適用され、sendRuleT 承認規則は topic1 にのみ適用されます。
sendRuleNS 承認規則を使用する場合は、クライアント アプリケーションで eh1 と topic1 の両方に送信できます。 sendRuleT 承認規則が使用されている場合、topic1 のみに詳細なアクセスが適用されるため、アクセスにこの規則を使用するクライアント アプリケーションでは、eh1 に送信できなくなり、topic1 にのみ送信できます。
Shared Access Signature トークンの生成
承認規則の名前とその署名キーの 1 つにアクセスできるクライアントは、SAS トークンを生成できます。 以下の形式で文字列を作成してトークンを生成します:
-
se– トークンの有効期限。 整数はトークンの有効期限が切れる1970年1月1日00:00:00 UTC以降の秒数を反映しています(UNIXエポック)。 -
skn– 承認規則の名前。これは SAS キー名です。 -
sr– アクセスされているリソースの URI。 -
sig– 署名。
署名文字列は、リソースURI(前節で説明したスコープ)上で計算された HMAC-SHA256 ハッシュと、行送り(LF)で区切られたトークンの有効期限瞬間の文字列表現です。 ハッシュに認可ルールの署名キーのいずれかをキー付けします。 ハッシュ計算は256ビット/32バイトのハッシュ値を返します。
HMAC-SHA256(signingKey, 'https://<yournamespace>.servicebus.windows.net/' + '\n' + 1438205742)
トークンには非ハッシュ化された値が含まれているため、受信者は同じパラメータでハッシュを再計算し、発行者が有効な署名鍵を持っているかを検証できます。
リソース URI とは、アクセスが要求される Service Bus リソースの完全な URI です。 例えば、 http://<namespace>.servicebus.windows.net/<entityPath> や sb://<namespace>.servicebus.windows.net/<entityPath>、例えば http://contoso.servicebus.windows.net/eh1。
URIをパーセントエンコードしてください。
このURIまたはその階層的親のいずれかが指定したエンティティに署名するためのSASルールを設定してください。 たとえば、前の例では、http://contoso.servicebus.windows.net/eh1 または http://contoso.servicebus.windows.net となります。
SAS トークンは、署名文字列で使われている <resourceURI> がプレフィックスになっているすべてのリソースで有効です。
Note
イベントハブ用のアクセストークンは共有アクセスポリシーを使って生成します。 詳細については、「Shared access authorization policy」 (共有アクセス承認ポリシー) を参照してください。
ポリシーから署名(トークン)を生成します
以下のセクションでは、共有アクセス署名ポリシーを使ってSASトークンを生成する方法を示します。
Node.js
function createSharedAccessToken(uri, saName, saKey) {
if (!uri || !saName || !saKey) {
throw "Missing required parameter";
}
var encoded = encodeURIComponent(uri);
var now = new Date();
var week = 60*60*24*7;
var ttl = Math.round(now.getTime() / 1000) + week;
var signature = encoded + '\n' + ttl;
var hash = crypto.createHmac('sha256', saKey).update(signature, 'utf8').digest('base64');
return 'SharedAccessSignature sr=' + encoded + '&sig=' +
encodeURIComponent(hash) + '&se=' + ttl + '&skn=' + saName;
}
ポリシー名とキー値を使用してイベント ハブに接続するには、EventHubProducerClient パラメーターを受け取る AzureNamedKeyCredential コンストラクターを使用します。
const producer = new EventHubProducerClient("NAMESPACE NAME.servicebus.windows.net", eventHubName, new AzureNamedKeyCredential("POLICYNAME", "KEYVALUE"));
AzureNamedKeyCredentialへの参照を追加します。
const { AzureNamedKeyCredential } = require("@azure/core-auth");
コードを使って生成するSASトークンを使うには、AzureSASCredentialパラメータを取るEventHubProducerClientコンストラクタを使います。
var token = createSharedAccessToken("https://NAMESPACENAME.servicebus.windows.net", "POLICYNAME", "KEYVALUE");
const producer = new EventHubProducerClient("NAMESPACENAME.servicebus.windows.net", eventHubName, new AzureSASCredential(token));
AzureSASCredentialへの参照を追加します。
const { AzureSASCredential } = require("@azure/core-auth");
Java
private static String GetSASToken(String resourceUri, String keyName, String key)
{
long epoch = System.currentTimeMillis()/1000L;
int week = 60*60*24*7;
String expiry = Long.toString(epoch + week);
String sasToken = null;
try {
String stringToSign = URLEncoder.encode(resourceUri, "UTF-8") + "\n" + expiry;
String signature = getHMAC256(key, stringToSign);
sasToken = "SharedAccessSignature sr=" + URLEncoder.encode(resourceUri, "UTF-8") +"&sig=" +
URLEncoder.encode(signature, "UTF-8") + "&se=" + expiry + "&skn=" + keyName;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return sasToken;
}
public static String getHMAC256(String key, String input) {
Mac sha256_HMAC = null;
String hash = null;
try {
sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
Encoder encoder = Base64.getEncoder();
hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return hash;
}
PHP
function generateSasToken($uri, $sasKeyName, $sasKeyValue)
{
$targetUri = strtolower(rawurlencode(strtolower($uri)));
$expires = time();
$expiresInMins = 60;
$week = 60*60*24*7;
$expires = $expires + $week;
$toSign = $targetUri . "\n" . $expires;
$signature = rawurlencode(base64_encode(hash_hmac('sha256',
$toSign, $sasKeyValue, TRUE)));
$token = "SharedAccessSignature sr=" . $targetUri . "&sig=" . $signature . "&se=" . $expires . "&skn=" . $sasKeyName;
return $token;
}
C#
private static string createToken(string resourceUri, string keyName, string key)
{
TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
var week = 60 * 60 * 24 * 7;
var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + week);
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
{
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
return sasToken;
}
}
PowerShell
[Reflection.Assembly]::LoadWithPartialName("System.Web")| out-null
$URI="myNamespace.servicebus.windows.net/myEventHub/"
$Access_Policy_Name="RootManageSharedAccessKey"
$Access_Policy_Key="myPrimaryKey"
#Token expires now+300
$Expires=([DateTimeOffset]::Now.ToUnixTimeSeconds())+300
$SignatureString=[System.Web.HttpUtility]::UrlEncode($URI)+ "`n" + [string]$Expires
$HMAC = New-Object System.Security.Cryptography.HMACSHA256
$HMAC.key = [Text.Encoding]::ASCII.GetBytes($Access_Policy_Key)
$Signature = $HMAC.ComputeHash([Text.Encoding]::ASCII.GetBytes($SignatureString))
$Signature = [Convert]::ToBase64String($Signature)
$SASToken = "SharedAccessSignature sr=" + [System.Web.HttpUtility]::UrlEncode($URI) + "&sig=" + [System.Web.HttpUtility]::UrlEncode($Signature) + "&se=" + $Expires + "&skn=" + $Access_Policy_Name
$SASToken
Bash
get_sas_token() {
local EVENTHUB_URI='EVENTHUBURI'
local SHARED_ACCESS_KEY_NAME='SHAREDACCESSKEYNAME'
local SHARED_ACCESS_KEY='SHAREDACCESSKEYVALUE'
local EXPIRY=${EXPIRY:=$((60 * 60 * 24))} # Default token expiry is 1 day
local ENCODED_URI=$(echo -n $EVENTHUB_URI | jq -s -R -r @uri)
local TTL=$(($(date +%s) + $EXPIRY))
local UTF8_SIGNATURE=$(printf "%s\n%s" $ENCODED_URI $TTL | iconv -t utf8)
local HASH=$(echo -n "$UTF8_SIGNATURE" | openssl sha256 -hmac $SHARED_ACCESS_KEY -binary | base64)
local ENCODED_HASH=$(echo -n $HASH | jq -s -R -r @uri)
echo -n "SharedAccessSignature sr=$ENCODED_URI&sig=$ENCODED_HASH&se=$TTL&skn=$SHARED_ACCESS_KEY_NAME"
}
SASでEvent Hubsのパブリッシャー認証
イベント パブリッシャーは Event Hub の仮想エンドポイントを定義します。 パブリッシャーは、イベント ハブへのメッセージ送信にのみ使用でき、メッセージ受信には使用できません。
通常、Event Hub はクライアントごとに 1 つのパブリッシャーを使用します。 Event Hub のパブリッシャーに送信されるすべてのメッセージは、その Event Hub 内でキューに格納されます。 パブリッシャーでは、きめの細かいアクセス制御を行うことができます。
一意のトークンが各 Event Hubs クライアントに割り当てられ、クライアントにアップロードされます。 トークンは、それぞれの一意なパブリッシャーにアクセスできるように生成されます。 トークンを保持するクライアントでは、1 つのパブリッシャーにのみ送信でき、それ以外のパブリッシャーには送信できません。 複数のクライアントが同じトークンを共有する場合、これらのクライアントそれぞれがパブリッシャーを共有します。
すべてのトークンは、SAS キーで割り当てられます。 通常、すべてのトークンは、同じキーで署名されます。 クライアントではキーが認識されません。そのため、クライアントがトークンを生成することはできません。 クライアントは、有効期限が切れるまで同じトークンで動作します。
例えば、Event Hubsへの送信または公開のみに限定した認可ルールを定義するには、送信認可ルールを定義する必要があります。 名前空間レベルでルールを作成することも、イベントハブのインスタンスやトピックなど特定のエンティティにより細かい範囲を与えることもできます。 この細かいアクセスを持つクライアントやアプリケーションはイベントハブパブリッシャーと呼ばれます。 この認証を設定するには、以下の手順に従ってください:
公開したいエンティティにSASキーを作成し、 送信 スコープを割り当てます。 詳細については、「Shared access authorization policies」 (共有アクセス承認ポリシー) を参照してください。
ステップ1で作成したキーを使って、特定の出版社に対して有効期限付きのSASトークンを生成します。 サンプルコードについては、「 ポリシーから署名(トークン)を生成する」を参照してください。
トークンを発行者クライアントに提供し、発行者はトークンがアクセスを許可する主体と発行者にのみ送信できます。
トークンが期限切れになると、クライアントはエンティティへの送信や公開のアクセス権を失います。
Note
推奨はしませんが、イベントハブや名前空間へのアクセスを可能にするトークンをデバイスに装備させることができます。 このトークンを保持するデバイスでは、そのイベント ハブにメッセージを直接送信できます。 デバイスがそのイベントハブに送信するのをブロックリストすることはできません。
特定の詳細なスコープを指定することをお勧めします。
Important
トークンを作成すると、各クライアントが固有のトークンを受け取ります。
クライアントがイベントハブにデータを送る際、そのリクエストにトークンをタグ付けします。 攻撃者による送信の傍受とトークンの盗難を防ぐために、クライアントと Event Hub 間の通信は暗号化されたチャネルを介して行う必要があります。
攻撃者がトークンを盗んだ場合、攻撃者は盗まれたクライアントを偽装することができます。 パブリッシャーを許可しないと、そのクライアントは別のパブリッシャーを使う新しいトークンを受け取るまで使用できなくなります。
SASでEvent Hubsの消費者を認証する
Event Hubs トークン認証を使用して、Event Hubs プロデューサーによって生成されたデータを利用するバックエンド アプリケーションを認証するには、そのクライアントに Event Hubs 名前空間またはイベント ハブ インスタンスまたはトピックに管理権限またはリッスン特権が割り当てられている必要があります。 Event Hubs からのデータは、コンシューマー グループを介して消費されます。 SAS ポリシーで詳細なスコープが提供されますが、このスコープは、コンシューマー レベルではなく、エンティティ レベルでのみ定義されます。 これは、名前空間レベルあるいはイベント ハブまたはトピックのレベルで定義された特権が、そのエンティティのコンシューマー グループに適用されることを意味します。
ローカルまたはSAS鍵認証を無効にしてください
組織のセキュリティ要件によっては、ローカルまたは SAS キー認証を完全に無効にし、Microsoft Entra ID ベースの認証を使用する必要があります。これは、Azure Event Hubs に接続するための推奨される方法です。 ローカルまたは SAS キー認証は、Azure portal または Azure Resource Manager テンプレートを使用して、Event Hubs 名前空間レベルで無効にできます。
ポータルを使ってローカルまたはSAS鍵認証を無効にしてください
Azure portal を使用して、特定の Event Hubs 名前空間のローカルまたは SAS キー認証を無効にできます。
Azure portal で Event Hubs 名前空間に移動します。
次の図に示すように、[概要] ページで、[ローカル認証] の [有効] を選びます。
[ローカル認証] ポップアップで、[無効] を選んでから、[OK] を選びます。
テンプレートを使ってローカルまたはSAS鍵認証を無効にします
以下の Azure Resource Manager テンプレート (ARM テンプレート) に示すように、disableLocalAuth プロパティを true に設定することで、特定の Event Hubs 名前空間のローカル認証を無効にできます。
{
"apiVersion": "2024-01-01",
"name": "[parameters('eventHubNamespaceName')]",
"type": "Microsoft.EventHub/Namespaces",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard",
"tier": "Standard"
},
"properties": {
"isAutoInflateEnabled": true,
"maximumThroughputUnits": 7,
"disableLocalAuth": true
},
"resources": [
{
"apiVersion": "2024-01-01",
"name": "[parameters('eventHubName')]",
"type": "EventHubs",
"dependsOn": [
"[concat('Microsoft.EventHub/namespaces/', parameters('eventHubNamespaceName'))]"
],
"properties": {
"messageRetentionInDays": "[parameters('messageRetentionInDays')]",
"partitionCount": "[parameters('partitionCount')]"
}
}
]
}
Samples
- 共有アクセス資格情報または既定の Azure 資格情報 ID を使用してイベント ハブにイベントを発行する方法については、GitHub のこちらの場所にある .NET サンプル #6 を参照してください。
- 共有アクセス資格情報または既定の Azure 資格情報 ID を使用してイベントを使用または処理する方法については、GitHub のこちらの場所にある .NET サンプル #5 を参照してください。
関連するコンテンツ
SAS認証について理解したところで、関連する記事をご覧ください:
- 共有アクセス署名を使ってイベントハブリソースへのアクセスを認可 する - 認可の概念を学びましょう。
- Microsoft Entra IDを使ってイベントハブへのアクセスを許可する - エンタープライズレベルのセキュリティを実装する。