ASP.NET Core에서 개발 중인 앱 비밀 스토리지 금고

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

작성자: Rick AndersonKirk Larkin

샘플 코드 보기 및 다운로드(다운로드 방법)

이 문서에서는 개발 머신에서 ASP.NET Core 앱에 대한 중요한 데이터를 관리하는 방법을 설명합니다. 암호 또는 기타 중요한 데이터를 소스 코드에 저장하지 마세요. 프로덕션 비밀은 개발 또는 테스트에 사용되어서는 안 됩니다. 비밀은 앱과 함께 배포해서는 안 됩니다. 대신 환경 변수 또는 Azure Key Vault와 같은 제어된 방법을 통해 프로덕션 비밀에 액세스해야 합니다. Azure Key Vault 구성 제공자로 Azure 테스트 및 프로덕션 암호를 저장하고 보호할 수 있습니다.

.NET 콘솔 앱에서 사용자 비밀을 사용하려면 이 GitHub 이슈를 참조하세요.

환경 변수

환경 변수는 코드 또는 로컬 구성 파일에 앱 비밀이 저장되지 않도록 하는 데 사용됩니다. 환경 변수는 이전에 지정된 모든 구성 소스에 대한 구성 값을 재정의합니다.

개별 사용자 계정 보안이 활성화된 ASP.NET Core 웹앱을 고려합니다. 기본 데이터베이스 연결 문자열은 DefaultConnection 키가 있는 프로젝트의 appsettings.json 파일에 포함됩니다. 기본 연결 문자열은 사용자 모드로 실행되며 암호가 필요하지 않은 LocalDB용입니다. 앱을 배포하는 동안 DefaultConnection 환경 변수의 값으로 키 값을 재정의할 수 있습니다. 환경 변수는 중요한 자격 증명을 사용하여 전체 연결 문자열을 저장할 수 있습니다.

Warning

환경 변수는 일반적으로 암호화되지 않은 일반 텍스트로 저장됩니다. 머신 또는 프로세스가 손상되면 신뢰할 수 없는 당사자가 환경 변수에 액세스할 수 있습니다. 사용자 비밀 공개를 방지하는 추가 조치가 필요할 수 있습니다.

: 구분 기호는 모든 플랫폼의 환경 변수 계층적 키에서 작동하지 않습니다. 이중 밑줄 __은 다음과 같습니다.

  • 모든 플랫폼에서 지원됩니다. 예를 들어 : 구분 기호는 Bash에서 지원되지 않지만 __은 지원됩니다.
  • 자동으로 :으로 대체

비밀 관리자

Secret Manager 도구는 애플리케이션 개발 중에 중요한 데이터를 저장합니다. 이 컨텍스트에서 중요한 데이터의 조각은 앱 비밀입니다. 앱 비밀은 프로젝트 트리와는 별도의 위치에 저장됩니다. 앱 비밀은 특정 프로젝트에 연결되거나 여러 프로젝트에서 공유됩니다. 앱 비밀이 소스 제어에 체크 인되지 않습니다.

Warning

비밀 관리자 도구는 저장된 비밀을 암호화하지 않으며 신뢰할 수 있는 저장소로 취급해서는 안 됩니다. 개발용으로만 사용됩니다. 키와 값은 사용자 프로필 디렉터리의 JSON 구성 파일에 저장됩니다.

비밀 관리자 도구의 작동 방식

비밀 관리자 도구는 값이 저장되는 위치 및 방법과 같은 구현 세부 정보를 숨깁니다. 이러한 구현 세부 정보를 몰라도 도구를 사용할 수 있습니다. 값은 로컬 컴퓨터의 사용자 프로필 폴더에 있는 JSON 파일에 저장됩니다.

파일 시스템 경로:

%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json

위의 파일 경로에서 <user_secrets_id>를 프로젝트 파일에 지정된 UserSecretsId 값으로 바꿉니다.

비밀 관리자 도구를 사용하여 저장된 데이터의 위치 또는 형식에 따라 달라지는 코드를 작성하지 마세요. 이러한 구현 세부 정보는 변경될 수 있습니다. 예를 들어 비밀 값은 암호화되지 않지만 나중에 암호화될 수 있습니다.

비밀 스토리지 사용

비밀 관리자 도구는 사용자 프로필에 저장된 프로젝트별 구성 설정에서 작동합니다.

CLI 사용

비밀 관리자 도구에는 init 명령이 포함되어 있습니다. 사용자 비밀을 사용하려면 프로젝트 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets init

이전 명령은 프로젝트 파일의 PropertyGroup 내에 UserSecretsId 요소를 추가합니다. 기본적으로 UserSecretsId의 내부 텍스트는 GUID입니다. 내부 텍스트는 임의적이지만 프로젝트에 고유합니다.

<PropertyGroup>
  <TargetFramework>netcoreapp3.1</TargetFramework>
  <UserSecretsId>79a3edd0-2092-40a2-a04d-dcb46d5ca9ed</UserSecretsId>
</PropertyGroup>

Visual Studio 사용

Visual Studio의 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 상황에 맞는 메뉴에서 사용자 비밀 관리를 선택합니다. 이 제스처는 GUID로 채워진 UserSecretsId 요소를 프로젝트 파일에 추가합니다.

GenerateAssemblyInfofalse인 경우

어셈블리 정보 특성 생성을 사용하지 않도록 설정한 경우 수동으로 추가AssemblyInfo.cs합니다UserSecretsIdAttribute. 예시:

[assembly: UserSecretsId("your_user_secrets_id")]

특성을 AssemblyInfo.cs수동으로 추가할 UserSecretsId 때 값은 UserSecretsId 프로젝트 파일의 값과 일치해야 합니다.

비밀 설정

키와 해당 값으로 구성된 앱 비밀을 정의합니다. 비밀은 프로젝트의 UserSecretsId 값과 연결됩니다. 예를 들어 프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets set "Movies:ServiceApiKey" "12345"

앞의 예제에서 콜론은 MoviesServiceApiKey 속성을 사용하는 개체 리터럴이어야 함을 나타냅니다.

비밀 관리자 도구는 다른 디렉터리에서도 사용할 수 있습니다. --project 옵션을 사용하여 프로젝트 파일이 있는 파일 시스템 경로를 제공합니다. 예시:

dotnet user-secrets set "Movies:ServiceApiKey" "12345" --project "C:\apps\WebApp1\src\WebApp1"

Visual Studio의 JSON 구조체 평면화

Visual Studio의 사용자 비밀 관리 제스처는 secrets.json 텍스트 편집기에서 파일을 엽니다. 콘텐츠를 secrets.json 저장할 키-값 쌍으로 바꿉니다. 예시:

{
  "Movies": {
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
    "ServiceApiKey": "12345"
  }
}

JSON 구조는 dotnet user-secrets remove 또는 dotnet user-secrets set를 통해 수정한 후에 평면화됩니다. 예를 들어 dotnet user-secrets remove "Movies:ConnectionString"을 실행하면 Movies 개체 리터럴이 축소됩니다. 수정된 파일은 다음 JSON과 유사합니다.

{
  "Movies:ServiceApiKey": "12345"
}

여러 비밀 설정

비밀 일괄 처리는 set 명령에 JSON을 파이프하여 설정할 수 있습니다. 다음 예제 input.json 에서는 파일의 내용이 명령에 파이프됩니다 set .

명령 셸을 열고 다음 명령을 실행합니다.

type .\input.json | dotnet user-secrets set

비밀 액세스

비밀에 액세스하려면 다음 단계를 완료합니다.

  1. 사용자 비밀 구성 소스 등록
  2. 구성 API를 통해 비밀 읽기

사용자 비밀 구성 소스 등록

사용자 비밀 구성 공급자는 .NET 구성 API를 사용하여 적절한 구성 소스를 등록합니다.

dotnet new 또는 Visual Studio를 사용하여 만든 ASP.NET Core 웹앱은 다음 코드를 생성합니다.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

WebApplication.CreateBuilder는 미리 구성된 기본값을 사용하여 WebApplicationBuilder 클래스의 새 인스턴스를 초기화합니다. 초기화된 WebApplicationBuilder(builder)는 기본 구성을 제공하고 EnvironmentNameDevelopment일 때 AddUserSecrets를 호출합니다.

구성 API를 통해 비밀 읽기

Movies:ServiceApiKey 키를 읽는 다음 예제를 고려하세요.

Program.cs 파일:

var builder = WebApplication.CreateBuilder(args);
var movieApiKey = builder.Configuration["Movies:ServiceApiKey"];

var app = builder.Build();

app.MapGet("/", () => movieApiKey);

app.Run();

Razor Pages 페이지 모델:

public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public void OnGet()
    {
        var moviesApiKey = _config["Movies:ServiceApiKey"];

        // call Movies service with the API key
    }
}

자세한 내용은 ASP.NET Core의 구성을 참조하세요.

POCO에 비밀 매핑

전체 개체 리터럴을 POCO(속성이 있는 간단한 .NET 클래스)에 매핑하면 관련 속성을 집계하는 데 유용합니다.

앱의 secrets.json 파일에 다음 두 비밀이 포함되어 있다고 가정합니다.

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

위의 비밀을 POCO에 매핑하려면 .NET 구성 API의 개체 그래프 바인딩 기능을 사용합니다. 다음 코드는 사용자 지정 MovieSettings POCO에 바인딩하고 ServiceApiKey 속성 값에 액세스합니다.

var moviesConfig = 
    Configuration.GetSection("Movies").Get<MovieSettings>();
_moviesApiKey = moviesConfig.ServiceApiKey;

Movies:ConnectionStringMovies:ServiceApiKey 비밀은 MovieSettings의 해당 속성에 매핑됩니다.

public class MovieSettings
{
    public string ConnectionString { get; set; }

    public string ServiceApiKey { get; set; }
}

비밀을 사용하여 문자열 대체

암호를 일반 텍스트로 저장하는 것은 안전하지 않습니다. 예를 들어 appsettings.json에 저장된 데이터베이스 연결 문자열에는 지정된 사용자에 대한 암호가 포함될 수 있습니다.

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;Password=pass123;MultipleActiveResultSets=true"
  }
}

보다 안전한 방법은 암호를 비밀로 저장하는 것입니다. 예시:

dotnet user-secrets set "DbPassword" "pass123"

appsettings.json의 연결 문자열에서 Password 키-값 쌍을 제거합니다. 예시:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;MultipleActiveResultSets=true"
  }
}

비밀 값은 SqlConnectionStringBuilder 개체의 Password 속성에 설정되어 연결 문자열을 완성할 수 있습니다.

using System.Data.SqlClient;

var builder = WebApplication.CreateBuilder(args);

var conStrBuilder = new SqlConnectionStringBuilder(
        builder.Configuration.GetConnectionString("Movies"));
conStrBuilder.Password = builder.Configuration["DbPassword"];
var connection = conStrBuilder.ConnectionString;

var app = builder.Build();

app.MapGet("/", () => connection);

app.Run();

비밀 나열

앱의 secrets.json 파일에 다음 두 비밀이 포함되어 있다고 가정합니다.

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets list

다음과 같은 출력이 표시됩니다.

Movies:ConnectionString = Server=(localdb)\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true
Movies:ServiceApiKey = 12345

앞의 예제에서 키 이름의 콜론은 내의 개체 계층 구조를 secrets.json나타냅니다.

단일 비밀 제거

앱의 secrets.json 파일에 다음 두 비밀이 포함되어 있다고 가정합니다.

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets remove "Movies:ConnectionString"

앱의 secrets.json 파일이 키와 Movies:ConnectionString 연결된 키-값 쌍을 제거하도록 수정되었습니다.

{
  "Movies": {
    "ServiceApiKey": "12345"
  }
}

dotnet user-secrets list는 다음 메시지를 표시합시다.

Movies:ServiceApiKey = 12345

모든 비밀 제거

앱의 secrets.json 파일에 다음 두 비밀이 포함되어 있다고 가정합니다.

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets clear

앱의 모든 사용자 비밀이 파일에서 secrets.json 삭제되었습니다.

{}

dotnet user-secrets list를 실행하면 다음 메시지가 표시됩니다.

No secrets configured for this application.

Visual Studio를 사용하여 사용자 비밀 관리

Visual Studio에서 사용자 비밀을 관리하려면 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 사용자 비밀 관리를 선택합니다.

사용자 비밀 관리를 보여주는 Visual Studio

ASP.NET Framework에서 ASP.NET Core로 사용자 비밀 마이그레이션

GitHub 문제를 참조하세요.

비 웹 애플리케이션의 사용자 비밀

대상 Microsoft.NET.Sdk.Web 프로젝트에는 사용자 비밀에 대한 지원이 자동으로 포함됩니다. 콘솔 애플리케이션과 같은 대상 Microsoft.NET.Sdk프로젝트의 경우 구성 확장 및 사용자 비밀 NuGet 패키지를 명시적으로 설치합니다.

PowerShell 사용:

Install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.Configuration.UserSecrets

.NET CLI 사용:

dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.UserSecrets

패키지가 설치되면 프로젝트를 초기화하고 웹앱과 동일한 방식으로 비밀을 설정합니다. 다음 예제에서는 "AppSecret" 키로 설정된 비밀의 값을 검색하는 콘솔 애플리케이션을 보여 줍니다.

using Microsoft.Extensions.Configuration;

namespace ConsoleApp;

class Program
{
    static void Main(string[] args)
    {
        IConfigurationRoot config = new ConfigurationBuilder()
            .AddUserSecrets<Program>()
            .Build();

        Console.WriteLine(config["AppSecret"]);
    }
}

추가 리소스

작성자: Rick Anderson, Kirk Larkin, Daniel RothScott Addie

샘플 코드 보기 및 다운로드(다운로드 방법)

이 문서에서는 개발 머신에서 ASP.NET Core 앱에 대한 중요한 데이터를 관리하는 방법을 설명합니다. 암호 또는 기타 중요한 데이터를 소스 코드에 저장하지 마세요. 프로덕션 비밀은 개발 또는 테스트에 사용되어서는 안 됩니다. 비밀은 앱과 함께 배포해서는 안 됩니다. 대신 환경 변수 또는 Azure Key Vault와 같은 제어된 방법을 통해 프로덕션 비밀에 액세스해야 합니다. Azure Key Vault 구성 제공자로 Azure 테스트 및 프로덕션 암호를 저장하고 보호할 수 있습니다.

환경 변수

환경 변수는 코드 또는 로컬 구성 파일에 앱 비밀이 저장되지 않도록 하는 데 사용됩니다. 환경 변수는 이전에 지정된 모든 구성 소스에 대한 구성 값을 재정의합니다.

개별 사용자 계정 보안이 활성화된 ASP.NET Core 웹앱을 고려합니다. 기본 데이터베이스 연결 문자열은 DefaultConnection 키가 있는 프로젝트의 appsettings.json 파일에 포함됩니다. 기본 연결 문자열은 사용자 모드로 실행되며 암호가 필요하지 않은 LocalDB용입니다. 앱을 배포하는 동안 DefaultConnection 환경 변수의 값으로 키 값을 재정의할 수 있습니다. 환경 변수는 중요한 자격 증명을 사용하여 전체 연결 문자열을 저장할 수 있습니다.

Warning

환경 변수는 일반적으로 암호화되지 않은 일반 텍스트로 저장됩니다. 머신 또는 프로세스가 손상되면 신뢰할 수 없는 당사자가 환경 변수에 액세스할 수 있습니다. 사용자 비밀 공개를 방지하는 추가 조치가 필요할 수 있습니다.

: 구분 기호는 모든 플랫폼의 환경 변수 계층적 키에서 작동하지 않습니다. 이중 밑줄 __은 다음과 같습니다.

  • 모든 플랫폼에서 지원됩니다. 예를 들어 : 구분 기호는 Bash에서 지원되지 않지만 __은 지원됩니다.
  • 자동으로 :으로 대체

비밀 관리자

Secret Manager 도구는 애플리케이션 개발 중에 중요한 데이터를 저장합니다. 이 컨텍스트에서 중요한 데이터의 조각은 앱 비밀입니다. 앱 비밀은 프로젝트 트리와는 별도의 위치에 저장됩니다. 앱 비밀은 특정 프로젝트에 연결되거나 여러 프로젝트에서 공유됩니다. 앱 비밀이 소스 제어에 체크 인되지 않습니다.

Warning

비밀 관리자 도구는 저장된 비밀을 암호화하지 않으며 신뢰할 수 있는 저장소로 취급해서는 안 됩니다. 개발용으로만 사용됩니다. 키와 값은 사용자 프로필 디렉터리의 JSON 구성 파일에 저장됩니다.

비밀 관리자 도구의 작동 방식

비밀 관리자 도구는 값이 저장되는 위치 및 방법과 같은 구현 세부 정보를 숨깁니다. 이러한 구현 세부 정보를 몰라도 도구를 사용할 수 있습니다. 값은 로컬 컴퓨터의 사용자 프로필 폴더에 있는 JSON 파일에 저장됩니다.

파일 시스템 경로:

%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json

위의 파일 경로에서 <user_secrets_id>를 프로젝트 파일에 지정된 UserSecretsId 값으로 바꿉니다.

비밀 관리자 도구를 사용하여 저장된 데이터의 위치 또는 형식에 따라 달라지는 코드를 작성하지 마세요. 이러한 구현 세부 정보는 변경될 수 있습니다. 예를 들어 비밀 값은 암호화되지 않지만 나중에 암호화될 수 있습니다.

비밀 스토리지 사용

비밀 관리자 도구는 사용자 프로필에 저장된 프로젝트별 구성 설정에서 작동합니다.

비밀 관리자 도구에는 .NET Core SDK 3.0.100 이상의 init 명령이 포함되어 있습니다. 사용자 비밀을 사용하려면 프로젝트 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets init

이전 명령은 프로젝트 파일의 PropertyGroup 내에 UserSecretsId 요소를 추가합니다. 기본적으로 UserSecretsId의 내부 텍스트는 GUID입니다. 내부 텍스트는 임의적이지만 프로젝트에 고유합니다.

<PropertyGroup>
  <TargetFramework>netcoreapp3.1</TargetFramework>
  <UserSecretsId>79a3edd0-2092-40a2-a04d-dcb46d5ca9ed</UserSecretsId>
</PropertyGroup>

Visual Studio의 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 상황에 맞는 메뉴에서 사용자 비밀 관리를 선택합니다. 이 제스처는 GUID로 채워진 UserSecretsId 요소를 프로젝트 파일에 추가합니다.

비밀 설정

키와 해당 값으로 구성된 앱 비밀을 정의합니다. 비밀은 프로젝트의 UserSecretsId 값과 연결됩니다. 예를 들어 프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets set "Movies:ServiceApiKey" "12345"

앞의 예제에서 콜론은 MoviesServiceApiKey 속성을 사용하는 개체 리터럴이어야 함을 나타냅니다.

비밀 관리자 도구는 다른 디렉터리에서도 사용할 수 있습니다. --project 옵션을 사용하여 프로젝트 파일이 있는 파일 시스템 경로를 제공합니다. 예시:

dotnet user-secrets set "Movies:ServiceApiKey" "12345" --project "C:\apps\WebApp1\src\WebApp1"

Visual Studio의 JSON 구조체 평면화

Visual Studio의 사용자 비밀 관리 제스처는 secrets.json 텍스트 편집기에서 파일을 엽니다. 콘텐츠를 secrets.json 저장할 키-값 쌍으로 바꿉니다. 예시:

{
  "Movies": {
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
    "ServiceApiKey": "12345"
  }
}

JSON 구조는 dotnet user-secrets remove 또는 dotnet user-secrets set를 통해 수정한 후에 평면화됩니다. 예를 들어 dotnet user-secrets remove "Movies:ConnectionString"을 실행하면 Movies 개체 리터럴이 축소됩니다. 수정된 파일은 다음 JSON과 유사합니다.

{
  "Movies:ServiceApiKey": "12345"
}

여러 비밀 설정

비밀 일괄 처리는 set 명령에 JSON을 파이프하여 설정할 수 있습니다. 다음 예제 input.json 에서는 파일의 내용이 명령에 파이프됩니다 set .

명령 셸을 열고 다음 명령을 실행합니다.

type .\input.json | dotnet user-secrets set

비밀 액세스

비밀에 액세스하려면 다음 단계를 완료합니다.

  1. 사용자 비밀 구성 소스 등록
  2. 구성 API를 통해 비밀 읽기

사용자 비밀 구성 소스 등록

사용자 비밀 구성 공급자는 .NET 구성 API를 사용하여 적절한 구성 소스를 등록합니다.

사용자 비밀 구성 소스는 프로젝트가 CreateDefaultBuilder를 호출할 때 개발 모드에서 자동으로 추가됩니다. EnvironmentNameDevelopment일 때 CreateDefaultBuilderAddUserSecrets를 호출합니다.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

CreateDefaultBuilder가 호출되지 않으면 ConfigureAppConfiguration에서 AddUserSecrets를 호출하여 사용자 비밀 구성 소스를 명시적으로 추가합니다. 다음 예제와 같이 개발 환경에서 앱이 실행되는 경우에만 AddUserSecrets를 호출합니다.

public class Program
{
    public static void Main(string[] args)
    {
        var host = new HostBuilder()
            .ConfigureAppConfiguration((hostContext, builder) =>
            {
                // Add other providers for JSON, etc.

                if (hostContext.HostingEnvironment.IsDevelopment())
                {
                    builder.AddUserSecrets<Program>();
                }
            })
            .Build();
        
        host.Run();
    }
}

구성 API를 통해 비밀 읽기

사용자 비밀 구성 소스가 등록되면 .NET 구성 API가 비밀을 읽을 수 있습니다. 생성자 주입을 사용하여 .NET 구성 API에 액세스할 수 있습니다. Movies:ServiceApiKey 키를 읽는 다음 예제를 고려하세요.

시작 클래스:

public class Startup
{
    private string _moviesApiKey = null;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        _moviesApiKey = Configuration["Movies:ServiceApiKey"];
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            var result = string.IsNullOrEmpty(_moviesApiKey) ? "Null" : "Not Null";
            await context.Response.WriteAsync($"Secret is {result}");
        });
    }
}

Razor Pages 페이지 모델:

public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public void OnGet()
    {
        var moviesApiKey = _config["Movies:ServiceApiKey"];

        // call Movies service with the API key
    }
}

자세한 내용은 시작 시 액세스 구성Razor 페이지의 액세스 구성을 참조하세요.

POCO에 비밀 매핑

전체 개체 리터럴을 POCO(속성이 있는 간단한 .NET 클래스)에 매핑하면 관련 속성을 집계하는 데 유용합니다.

앱의 secrets.json 파일에 다음 두 비밀이 포함되어 있다고 가정합니다.

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

위의 비밀을 POCO에 매핑하려면 .NET 구성 API의 개체 그래프 바인딩 기능을 사용합니다. 다음 코드는 사용자 지정 MovieSettings POCO에 바인딩하고 ServiceApiKey 속성 값에 액세스합니다.

var moviesConfig = 
    Configuration.GetSection("Movies").Get<MovieSettings>();
_moviesApiKey = moviesConfig.ServiceApiKey;

Movies:ConnectionStringMovies:ServiceApiKey 비밀은 MovieSettings의 해당 속성에 매핑됩니다.

public class MovieSettings
{
    public string ConnectionString { get; set; }

    public string ServiceApiKey { get; set; }
}

비밀을 사용하여 문자열 대체

암호를 일반 텍스트로 저장하는 것은 안전하지 않습니다. 예를 들어 appsettings.json에 저장된 데이터베이스 연결 문자열에는 지정된 사용자에 대한 암호가 포함될 수 있습니다.

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;Password=pass123;MultipleActiveResultSets=true"
  }
}

보다 안전한 방법은 암호를 비밀로 저장하는 것입니다. 예시:

dotnet user-secrets set "DbPassword" "pass123"

appsettings.json의 연결 문자열에서 Password 키-값 쌍을 제거합니다. 예시:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;MultipleActiveResultSets=true"
  }
}

비밀 값은 SqlConnectionStringBuilder 개체의 Password 속성에 설정되어 연결 문자열을 완성할 수 있습니다.

public class Startup
{
    private string _connection = null;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        var builder = new SqlConnectionStringBuilder(
            Configuration.GetConnectionString("Movies"));
        builder.Password = Configuration["DbPassword"];
        _connection = builder.ConnectionString;

        // code omitted for brevity
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            await context.Response.WriteAsync($"DB Connection: {_connection}");
        });
    }
}

비밀 나열

앱의 secrets.json 파일에 다음 두 비밀이 포함되어 있다고 가정합니다.

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets list

다음과 같은 출력이 표시됩니다.

Movies:ConnectionString = Server=(localdb)\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true
Movies:ServiceApiKey = 12345

앞의 예제에서 키 이름의 콜론은 내의 개체 계층 구조를 secrets.json나타냅니다.

단일 비밀 제거

앱의 secrets.json 파일에 다음 두 비밀이 포함되어 있다고 가정합니다.

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets remove "Movies:ConnectionString"

앱의 secrets.json 파일이 키와 MoviesConnectionString 연결된 키-값 쌍을 제거하도록 수정되었습니다.

{
  "Movies": {
    "ServiceApiKey": "12345"
  }
}

dotnet user-secrets list는 다음 메시지를 표시합시다.

Movies:ServiceApiKey = 12345

모든 비밀 제거

앱의 secrets.json 파일에 다음 두 비밀이 포함되어 있다고 가정합니다.

{
  "Movies:ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
  "Movies:ServiceApiKey": "12345"
}

프로젝트 파일이 있는 디렉터리에서 다음 명령을 실행합니다.

dotnet user-secrets clear

앱의 모든 사용자 비밀이 파일에서 secrets.json 삭제되었습니다.

{}

dotnet user-secrets list를 실행하면 다음 메시지가 표시됩니다.

No secrets configured for this application.

Visual Studio를 사용하여 사용자 비밀 관리

Visual Studio에서 사용자 비밀을 관리하려면 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 사용자 비밀 관리를 선택합니다.

사용자 비밀 관리를 보여주는 Visual Studio

ASP.NET Framework에서 ASP.NET Core로 사용자 비밀 마이그레이션

GitHub 문제를 참조하세요.

비 웹 애플리케이션의 사용자 비밀

대상 Microsoft.NET.Sdk.Web 프로젝트에는 사용자 비밀에 대한 지원이 자동으로 포함됩니다. 콘솔 애플리케이션과 같은 대상 Microsoft.NET.Sdk프로젝트의 경우 구성 확장 및 사용자 비밀 NuGet 패키지를 명시적으로 설치합니다.

PowerShell 사용:

Install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.Configuration.UserSecrets

.NET CLI 사용:

dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.UserSecrets

패키지가 설치되면 프로젝트를 초기화하고 웹앱과 동일한 방식으로 비밀을 설정합니다. 다음 예제에서는 "AppSecret" 키로 설정된 비밀의 값을 검색하는 콘솔 애플리케이션을 보여 줍니다.

using Microsoft.Extensions.Configuration;

namespace ConsoleApp;

class Program
{
    static void Main(string[] args)
    {
        IConfigurationRoot config = new ConfigurationBuilder()
            .AddUserSecrets<Program>()
            .Build();

        Console.WriteLine(config["AppSecret"]);
    }
}

추가 리소스