当社は、お客様の1人から毎日ファイルを受け取ります。これは、XMLに変換され、SFTPサーバーからダウンロードされたEDIFACTファイルです。
次のような1つの(c#コンソール)アプリケーションを開発しました。
SQL-ServerおよびSQL-Serverエージェントサービスは、LocalSystem
アカウントとして開始されます。 (間もなく交換されるので、そのままにしておくことをお勧めします。正しく構成されていないことがわかっています。)
SQL-Serverにファイルを保存する手順は、次の手順と似ています。
CREATE PROCEDURE [dbo].[sp_ProviderName_Download]
(
-- FQN of XML file
@file_name nvarchar(260)
)
AS
BEGIN
DECLARE @xml_data XML,
@cmd nvarchar(max);
BEGIN TRY
SET @cmd = 'SELECT @xmlText = BulkColumn FROM OPENROWSET(BULK '
+ '''' + @file_name + ''''
+ ', SINGLE_BLOB) x;';
EXEC sp_executesql @cmd, N'@xmlText XML OUTPUT', @xmlText = @xml_data OUTPUT;
INSERT INTO [dbo].[ProviderXML_Register] (..., xml_data)
VALUES (..., @xml_data);
RETURN 0;
END TRY
BEGIN CATCH
EXEC [dbo].[vsp_error_handler];
RETURN -1;
END CATCH
END
問題:
ストアドプロシージャは、C#アプリケーションでのConnectionStringの設定方法に応じて機能します。
IntegratedSecurity = falseを使用する場合:
this.scsb = new SqlConnectionStringBuilder();
this.scsb.ApplicationName = "ProviderXML_Download";
this.scsb.WorkstationID = Environment.MachineName;
this.scsb.DataSource = "xxx.xxx.xxx.xxx";
this.scsb.InitialCatalog = "my_db";
this.scsb.IntegratedSecurity = false;
this.scsb.Password = "*******";
this.scsb.UserID = "SqlServerLogin";
エラーなしで正常に動作します。
ただし、IntegratedSecurity = trueを使用して接続する場合(ADユーザー)
this.scsb = new SqlConnectionStringBuilder();
this.scsb.ApplicationName = "ProviderXML_Download";
this.scsb.WorkstationID = Environment.MachineName;
this.scsb.DataSource = "SQL_INSTANCE_NAME";
this.scsb.InitialCatalog = "my_db";
this.scsb.IntegratedSecurity = true;
エラーで失敗します:
オペレーティングシステムエラー5アクセスが拒否されました。
ADユーザーは、ネットワーク共有に対する変更権限を持っています。そして、私の知る限り、「LocalSystem」アカウントはネットワーク共有にアクセスできません。
問題は、一括操作および偽装のデフォルトの制限に対するセキュリティの処理方法が原因です。
SQL Serverログインで接続する場合、外部Windows SID /セキュリティコンテキストはないため、SQL Serverは、SQL Serverの外部にアクセスする必要がある場合(つまり、OS、ネットワークなどと対話する場合)にサービスアカウントのセキュリティコンテキストを使用します。したがって、SQL Serverサービスアカウントがローカルシステムアカウントである場合、それは外部アクセスに使用されるアカウントです。ファイルはネットワーク上にあるため、「ローカルシステム」がそのネットワーク共有にアクセスできる必要があります。これは、サーバー自体にアクセスを許可することで可能になります(NTFSアクセス許可に<domain_name>\<computer_name> $を指定して)。この場合、SQL Serverプロセスは偽装を使用していません。外部アクセスは、プロセス自体のセキュリティコンテキストで行われています。
Windowsログインを使用してSQL Serverに接続するとき(サーバー上のADアカウントかローカルアカウントかに関係なく)、使用するSIDがあり、SQL Serverは外部アクセスにそのSID(Windows/ADアカウントを指すセキュリティID)を使用します。これは、「統合セキュリティ」/「Trusted_Connection」= true
で接続すると何が起こるかです。 SQL ServerにログインしているアカウントのSIDを使用すると、SQL Serverが偽装を使用して、ネットワーク要求appearが「ローカルシステム"(サービスアカウントはsqlservr.exe
プロセスを所有しており、ネットワークリクエストを行っているのはSQL ServerにログインしているSIDではなく、そのプロセスです)。偽装は、デフォルトで、プロセスが開始されたマシンに隔離されます(EXECUTE AS user
による偽装の使用がデフォルトでデータベースに隔離されるのと同様)。したがって、BULK INSERT
/OPENROWSET(BULK...
コマンドは、SQL Serverが実行されているサーバー上のファイルをローカルで表示できるはずですが、ネットワーク共有はローカルではなく、偽装されたセキュリティコンテキストはデフォルトでは表示されません。そこまで伸ばしてください。ここに表示されているものは、悪名高い「ダブルホップ」問題と同じものです。
したがって、次のいずれかを実行できます。
EVERYONE
に付与します「委任」を有効にしますが、それがローカルシステムアカウントで機能するかどうかはわかりません(SQL Serverエージェントは「ローカルシステム」として実行されているため、これがSQL Serverに接続します)。ローカルサーバーを超えることができるように、ADアカウントを設定し、そのアカウントに「委任」を有効にする必要がある場合があります。どちらの場合も、「委任」とは、アカウント(おそらくアカウントとサービスの組み合わせ)のアクセス許可が既定の検疫を超えるようにADを構成する方法です。
追伸@StrayCatDBAは、ネットワークサービスアカウント(つまりNT AUTHORITY\NETWORK SERVICE)を使用すると委任が可能になると述べました。また、「Windowsサービスアカウントとアクセス許可の設定"下部にあるリンクをクリックすると、そのドキュメントがさまざまなオプションについて説明されます。
ここにいくつかの情報: