EXECUTE AS 句 (Transact-SQL)

適用対象: SQL Server Azure SQL Database Azure SQL Managed Instance

SQL Server では、関数 (インライン テーブル値関数を除く)、プロシージャ、キュー、トリガーなどのユーザー定義モジュールの実行コンテキストを定義できます。

モジュールが実行されるコンテキストを指定することにより、データベース エンジンがどのユーザー アカウントを使用して、モジュールによって参照されるオブジェクトの権限を検証するかを制御できます。 これにより、ユーザー定義モジュールとそれらのモジュールによって参照されるオブジェクト間に存在する、オブジェクトのチェーン全体に関する権限の管理を、さらに柔軟に制御できます。 ユーザーに付与する必要のある権限は、モジュール自体に対するもののみで、参照されるオブジェクトに対する明示的な権限の許可は必要ありません。 モジュールによってアクセスされるオブジェクトに対する権限が必要なのは、そのモジュールを実行しているユーザーのみです。

Transact-SQL 構文表記規則

構文

このセクションでは、 EXECUTE ASの SQL Server 構文について説明します。

関数 (インライン テーブル値関数を除く)、ストアド プロシージャ、および DML トリガー:

{ EXEC | EXECUTE } AS { CALLER | SELF | OWNER | 'user_name' }

データベース スコープを持つ DDL トリガー:

{ EXEC | EXECUTE } AS { CALLER | SELF | 'user_name' }

サーバー スコープとログオン トリガーを含む DDL トリガー:

{ EXEC | EXECUTE } AS { CALLER | SELF | 'login_name' }

キュー:

{ EXEC | EXECUTE } AS { SELF | OWNER | 'user_name' }

引数

CALLER

モジュール内のステートメントを、モジュールの呼び出し元のコンテキストで実行します。 モジュールを実行するユーザーは、モジュール自体に対してだけでなく、そのモジュールによって参照されるすべてのデータベース オブジェクトに対する、適切な権限を持っている必要があります。

CALLER は、キューを除くすべてのモジュールの既定値であり、SQL Server 2005 (9.x) の動作と同じです。

CALLER は、 CREATE QUEUE または ALTER QUEUE ステートメントで指定できません。

SELF

EXECUTE AS SELF は、モジュールを作成または変更するユーザーが指定されたユーザーである EXECUTE AS <user_name>と同じです。 モジュールを作成または変更するユーザーの実際のユーザー ID は、sys.sql_modulesまたはsys.service_queues カタログ ビューのexecute_as_principal_id列に格納されます。

SELF はキューの既定値です。

Note

sys.service_queues カタログ ビューのexecute_as_principal_id列のユーザー ID を変更するには、ALTER QUEUE ステートメントでEXECUTE AS設定を明示的に指定する必要があります。

OWNER

モジュール内のステートメントが、モジュールの現在の所有者のコンテキストで実行されることを指定します。 モジュールに指定された所有者がない場合は、モジュールのスキーマの所有者が使用されます。 OWNER DDL またはログオン トリガーには指定できません。

重要

OWNER はシングルトン アカウントにマップする必要があり、ロールまたはグループにすることはできません。

'user_name'

モジュール内のステートメントを、user_name で指定されたユーザーのコンテキスト内で実行します。 モジュール内のすべてのオブジェクトの権限は user_name に対して検証されます。 サーバー スコープまたはログオン トリガーを持つ DDL トリガーには、user_name を指定できません。 代わりに login_name を使います。

user_name は、現在のデータベース内に存在し、単一アカウントである必要があります。 user_name グループ、ロール、証明書、キー、または組み込みアカウント ( NT AUTHORITY\LocalServiceNT AUTHORITY\NetworkServiceNT AUTHORITY\LocalSystemなど) にすることはできません。

実行コンテキストのユーザー ID はメタデータに格納され、sys.sql_modulesまたはsys.assembly_modules カタログ ビューのexecute_as_principal_id列に表示できます。

'login_name'

モジュール内部のステートメントを、login_name で指定された SQL Server ログインのコンテキストで実行します。 モジュール内のすべてのオブジェクトの権限は login_name に対して検証されます。 login_name は、サーバー スコープの DDL トリガーまたはログオン トリガーのみに指定できます。

login_name グループ、ロール、証明書、キー、または組み込みアカウント ( NT AUTHORITY\LocalServiceNT AUTHORITY\NetworkServiceNT AUTHORITY\LocalSystemなど) にすることはできません。

解説

データベース エンジンによる、モジュール内で参照されるオブジェクトに対する権限の評価方法は、呼び出し元のオブジェクトと参照されるオブジェクト間に存在する所有権の継承によって異なります。 以前のバージョンの SQL Server では、呼び出し元のユーザーに対して、参照されるすべてのオブジェクトへのアクセスを許可するためには、所有権の継承を使用する方法しかありませんでした。

所有権の継承には、次のような制限があります。

  • DML ステートメント ( SELECTINSERTUPDATEDELETE) にのみ適用されます。
  • 呼び出し元のオブジェクトと呼び出されたオブジェクトの所有者は同一である必要があります。
  • モジュール内の動的クエリには適用されません。

モジュール内で指定される実行コンテキストに関係なく、次の操作が常に適用されます。

  • モジュールが実行されると、データベース エンジンは最初に、モジュールを実行しているユーザーがモジュールに対するEXECUTEアクセス許可を持っていることを確認します。

  • 所有権の継承ルールは、引き続き適用されます。 つまり、呼び出し元のオブジェクトと呼び出されたオブジェクトの所有者が同一の場合、基になるオブジェクトに対する権限は確認されません。

ユーザーが、 CALLER以外のコンテキストで実行するように指定されたモジュールを実行すると、モジュールを実行するユーザーのアクセス許可がチェックされますが、モジュールによってアクセスされるオブジェクトに対する追加のアクセス許可チェックは、 EXECUTE AS 句で指定されたユーザー アカウントに対して実行されます。 実質的に、モジュールを実行するユーザーは、指定されたユーザーの権限を借用します。

モジュールの EXECUTE AS 句で指定されたコンテキストは、モジュールの実行期間中のみ有効です。 モジュールの実行が完了すると、コンテキストは呼び出し元に戻されます。

ユーザーまたはログイン名を指定する

モジュールの EXECUTE AS 句で指定されたデータベース ユーザーまたはサーバー ログインは、モジュールが別のコンテキストで実行されるように変更されるまで削除できません。

EXECUTE AS句で指定されたユーザー名またはログイン名は、それぞれ sys.database_principals または sys.server_principals のプリンシパルとして存在する必要があります。そうしないと、モジュールの作成または変更操作が失敗します。 また、モジュールを作成または変更するユーザーには、そのプリンシパルに対する IMPERSONATE 権限が必要です。

ユーザーが Windows グループ メンバーシップを介して SQL Server のデータベースまたはインスタンスに暗黙的にアクセスできる場合、 EXECUTE AS 句で指定されたユーザーは、次のいずれかの要件が存在する場合にモジュールが作成されるときに暗黙的に作成されます。

  • 指定されたユーザーまたはログインが、固定サーバー ロール sysadmin のメンバーであること。
  • モジュールを作成するユーザーに、プリンシパルを作成する権限が与えられていること。

これらの要件がどちらも満たされない場合、モジュールの作成操作は失敗します。

重要

SQL Server (MSSQLSERVER) サービスがローカル アカウント (ローカル サービスまたはローカル ユーザー アカウント) として実行されている場合、 EXECUTE AS 句で指定されている Windows ドメイン アカウントのグループ メンバーシップを取得する権限はありません。 このため、モジュールの実行は失敗します。

たとえば、次のような条件を想定します。

  • CompanyDomain\SQLUsers グループは、 Sales データベースにアクセスできます。

  • CompanyDomain\SqlUser1SQLUsers のメンバーであるため、 Sales データベースにアクセスできます。

  • モジュールを作成または変更するユーザーに、プリンシパルを作成する権限が与えられている。

次の CREATE PROCEDURE ステートメントが実行されると、CompanyDomain\SqlUser1 が、Sales データベースのデータベース プリンシパルとして暗黙的に作成されます。

USE Sales;
GO
CREATE PROCEDURE dbo.usp_Demo
WITH EXECUTE AS 'CompanyDomain\SqlUser1'
AS
SELECT USER_NAME();
GO

EXECUTE AS CALLER スタンドアロン ステートメントを使用する

モジュール内の EXECUTE AS CALLER スタンドアロン ステートメントを使用して、モジュールの呼び出し元に実行コンテキストを設定します。

次のストアド プロシージャが SqlUser2 によって呼び出されるとします。

CREATE PROCEDURE dbo.usp_Demo
WITH EXECUTE AS 'SqlUser1'
AS
SELECT USER_NAME(); -- Shows execution context is set to SqlUser1.
EXECUTE AS CALLER;
SELECT USER_NAME(); -- Shows execution context is set to SqlUser2, the caller of the module.
REVERT;
SELECT USER_NAME(); -- Shows execution context is set to SqlUser1.
GO

EXECUTE AS を使用してカスタム アクセス許可セットを定義する

モジュールの実行コンテキストを指定すると、カスタム アクセス許可セットを定義する場合に便利です。 たとえば、 TRUNCATE TABLE などの一部のアクションには、許可可能なアクセス許可がありません。 モジュール内に TRUNCATE TABLE ステートメントを組み込み、テーブルを変更するアクセス許可を持つユーザーとしてモジュールを実行するように指定することで、モジュールに対するアクセス許可を付与するユーザーにテーブルを切り捨てる権限 EXECUTE 拡張できます。

実行コンテキストを指定したモジュールの定義を表示するには、sys.sql_modules (Transact-SQL) カタログ ビューを使用します。

ベスト プラクティス

モジュール内で定義された操作を実行する場合に必要となる最低限の権限を持つログインまたはユーザーを指定します。 たとえば、これらのアクセス許可が必要な場合を除き、データベース所有者アカウントを指定しないでください。

アクセス許可

EXECUTE ASで指定されたモジュールを実行するには、呼び出し元にモジュールに対するEXECUTEアクセス許可が必要です。

別のデータベースまたはサーバー内のリソースにアクセスする EXECUTE AS で指定された CLR モジュールを実行するには、ターゲット データベースまたはサーバーは、モジュールの送信元データベース (ソース データベース) の認証子を信頼する必要があります。

モジュールの作成時または変更時に EXECUTE AS 句を指定するには、指定したプリンシパルに対する IMPERSONATE 権限と、モジュールを作成するためのアクセス許可が必要です。 ユーザー自身の権限は、常に借用できます。 実行コンテキストが指定されていない場合、または EXECUTE AS CALLER が指定されている場合、 IMPERSONATE アクセス許可は必要ありません。

Windows グループ メンバーシップを介してデータベースに暗黙的にアクセスできる login_name または user_name を指定するには、データベースに対する CONTROL 権限が必要です。

次の例では、AdventureWorks2022 データベースでストアド プロシージャを作成して、実行コンテキストを OWNER に割り当てます。

CREATE PROCEDURE HumanResources.uspEmployeesInDepartment @DeptValue INT
    WITH EXECUTE AS OWNER
AS
SET NOCOUNT ON;

SELECT e.BusinessEntityID,
    c.LastName,
    c.FirstName,
    e.JobTitle
FROM Person.Person AS c
INNER JOIN HumanResources.Employee AS e
    ON c.BusinessEntityID = e.BusinessEntityID
INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh
    ON e.BusinessEntityID = edh.BusinessEntityID
WHERE edh.DepartmentID = @DeptValue
ORDER BY c.LastName,
    c.FirstName;
GO

-- Execute the stored procedure by specifying department 5.
EXECUTE HumanResources.uspEmployeesInDepartment 5;
GO