Notre société reçoit un dossier quotidien de l'un de nos clients. C'est un fichier EDIFACT traduit en XML et téléchargé à partir d'un serveur SFTP.
Nous avons développé une application (C # Console) qui:
Le service agent SQL-Server & SQL-Server initie comme compte LocalSystem
. (Il sera rapidement remplacé et je préférerais le laisser comme c'est le cas, je sais que cela n'est pas configuré correctement.)
La procédure pour stocker le fichier dans notre serveur SQL est similaire à celle-ci:
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
le problème:
La procédure stockée fonctionne en fonction de la manière dont nous définissons les connexions dans notre application C #.
S'il utilise intégréSecurity = 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";
Cela fonctionne correctement sans erreurs.
Mais si cela se connecte à l'aide de IntegratedSecurity = TRUE (utilisateur 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;
il échoue avec une erreur:
Erreur du système d'exploitation 5 Accès refusé.
L'utilisateur AD a modifié les droits sur la part du réseau. Et autant que je sache, le compte "localysystem" ne devrait pas être en mesure d'accéder à la part du réseau.
Le problème est due à la manière dont la sécurité est traitée pour les opérations en vrac et les limitations par défaut de l'impersonnation.
Lorsque vous connectez avec une connexion SQL Server, il n'existe aucun contexte Windows Sid/Security externe, SQL Server utilise donc le contexte de sécurité du compte de service lorsque vous devez atteindre l'extérieur de SQL Server (c'est-à-dire interagir avec le système d'exploitation, réseau, etc.). Ainsi, si le compte de service SQL Server est le compte système local, c'est le compte utilisé pour un accès externe. Étant donné que votre fichier est sur le réseau, il faudrait que ce "système local" ait accès à cette part de réseau. Cela est possible en donnant au serveur lui-même accès (en spécifiant <nom_formé>\<nom_formé> $ pour les autorisations NTFS). Dans ce cas, le processus SQL Server n'utilise pas l'impersonnation: l'accès externe est effectué dans le contexte de sécurité du processus lui-même.
Lors de la connexion à SQL Server à l'aide d'une connexion Windows (compte de compte d'AD ou de compte local sur le serveur), il existe un SID à utiliser et SQL Server utilisera ce SID (ID de sécurité qui pointe sur le compte Windows/AD) pour un accès externe. . C'est ce qui se passe lors de la connexion à la "sécurité intégrée"/"fiducies_connection" = true
. Maintenant, à l'aide du SID de la connexion de compte dans SQL Server signifie que SQL Server utilise l'impersonnation pour que sa demande de réseau apparaisse Pour venir de cet autre SID au lieu de "Système local" (rappelez-vous , le compte de service possède le sqlservr.exe
Processus, et c'est ce processus, pas la connexion SID dans SQL Server, qui fait la demande de réseau). L'impersonnation, par défaut, est mise en quarantaine sur la machine dans laquelle le processus a été démarré (semblable à la manière dont l'utilisation de l'impersonnation via EXECUTE AS user
est, par défaut, mise en quarantaine à la base de données). Alors le BULK INSERT
/OPENROWSET(BULK...
Les commandes doivent pouvoir voir des fichiers localement sur le serveur que SQL Server s'allume, mais les actions réseau ne sont pas locales et le contexte de sécurité impersonnée, par défaut, ne prolonge pas cela loin. Ce que vous voyez ici devrait Soyez la même chose que le problème infâme "double-hop".
Donc, vous pouvez faire l'une des opérations suivantes:
EVERYONE
Activer la "délégation", bien que je ne sois pas sûr que cela fonctionnera sur un compte système local (vous avez mentionné SQL Server Agent exécuté comme "Système local", c'est donc ce qui se connecterait à SQL Server). Cela peut nécessiter une mise en place d'un compte d'annonces et permettre à ce compte de "délégation" afin qu'il puisse aller au-delà du serveur local. De toute façon, la "délégation" est la manière dont on configure une annonce pour autoriser un compte (peut-être même une combinaison de compte/service) d'aller au-delà de la quarantaine par défaut.
P.s. @Straycatdba a mentionné que l'utilisation du compte de service réseau (c.-à-d. NT Authority\Service permet une délégation. Aussi, veuillez consulter "Configurer les comptes de service Windows et les autorisations "Link en bas car cette documentation passe sur les différentes options que vous avez.
Quelques informations ici: