Elixir 비밀에 대한 AWS SSM 파라미터
안티패턴
Elixir 1.9가 도입되었습니다"releases". 구성 방법에 대한 설명overhaul이 있습니다. 그 전에는 모든 구성이 빌드 시간에 해결되었습니다. "빌드 시간"과 "실행 시간"이 사실상 동일했기 때문에 "소스에서"앱을 실행하는 사람들에게는 문제가 되지 않았습니다. 그러나 미리 빌드된 앱을 제공하려는 사람들에게는 문제가 발생했습니다.
config :my_app,
# when is this resolved?
database_url: System.get_env("DATABASE_URL")
사람들은 패턴을 채택하여 이 문제를 해결했습니다. 즉, 변수를 자리 표시자 값으로 설정하고 나중에 조회를 연기합니다.
config :my_app,
normal_var: "I am totally normal",
deferred_var: {:system, "SEE_YOU_LATER"}
이것이 작동하려면 소비 코드가 이 패턴을 인식해야 합니다.
def consume_config() do
case Application.get_env(:my_app, :deferred_var) do
{:system, var} -> System.get_env(var)
value -> value
end
end
이 "안티 패턴"의 문제는 이것이 실제 기능이 아니라 구성 시스템 자체의 기능이라고 잘못 가정한 신규 사용자를 혼란스럽게 한다는 것입니다. 지원을 선택했습니다.
다행스럽게도 이것은 더 이상 문제가 되지 않으며 런타임 구성에 대한 이야기가 훨씬 더 좋습니다. 모든 것을 config/runtime.exs
에 넣기만 하면 됩니다.
최근에는 AWS SSM을 사용하여 secret configuration을 저장하고 싶었는데, 방법은 Config.Provider을 사용하는 것 같았습니다. 다른 사람들이 같은 문제를 어떻게 해결했는지 둘러보니 익숙한 패턴이 나타났습니다.
config :my_app,
some_var: {:ssm, "THIS_LOOKS_FAMILIAR"}
Config.Provider
s가 config/runtime.exs
이후에 실행되기 때문에 나중에 감지하고 바꿀 수 있는 자리 표시자 값이 필요했습니다.
이것은 동일한 안티 패턴의 예라고 생각했습니다.
안티 패턴을 다시 도입하고 싶지 않다고 결정하고 다른 접근 방식을 생각해 냈습니다.
다른 접근법
먼저 필요한 종속성을 추가하고 Config.Provider
를 선언합니다.
defmodule Example.MixProject do
def project do
[
...
releases: releases()
]
end
defp releases() do
[
example: [
config_providers: [
{Example.ConfigProvider, []}
]
]
]
end
defp deps do
[
...
{:ex_aws, "2.0"},
{:ex_aws_ssm, "2.0"}
]
end
end
그리고 아래와 같이 구현합니다.
defmodule Example.ConfigProvider do
@behaviour Config.Provider
@impl true
def init([]) do
[]
end
@impl true
def load(config, _state) do
{:ok, _} = Application.ensure_all_started(:hackney)
{:ok, _} = Application.ensure_all_started(:ex_aws)
params = get_parameters(config[:ex_aws]) |> Enum.into(%{})
Config.Reader.merge(config,
example: [
{ExampleWeb.Endpoint, secret_key_base: params["secret_key_base"]},
{Example.Repo, url: params["database_url"]}
]
)
end
defp get_parameters(config) do
ExAws.SSM.get_parameters_by_path(prefix(), with_decryption: true)
|> ExAws.request(config)
|> case do
{:ok, %{"Parameters" => params}} ->
params
|> Enum.map(fn param ->
{String.trim_leading(param["Name"], prefix()), param["Value"]}
end)
error ->
raise "Failed to fetch parameters: #{inspect(error)}"
end
end
defp prefix() do
"/example/prod/"
end
end
본질적으로 자리 표시자 값에 의존하는 제네릭Config.Provider
을 사용하는 대신 원하는 구성을 추가하는 일회성Config.Provider
을 작성했습니다.
잃어버린 것을 되찾는 것
이것은 내가 작업하고 있는 프로젝트에서 잘 작동했지만, 돌이켜보면 두 가지 문제가 있는 것 같습니다.
"잘못된"접근 방식에는 좋은 점이 있었습니다. 선언적이었고 구성이 모두 한 곳에 있었습니다.
나는 코드가 잃어버린 명확성을 되찾는 데 도움이 될 대안에 대해 생각했고 이것이 내가 생각해 낸 것입니다.
먼저 가능한 가장 간단한 API로 시작했습니다.
config :my_app,
some_var: System.get_env("SOME_VAR"),
database_url: Secret.get_env("DATABASE_URL")
System.get_env(...)
를 Secret.get_env(...)
로 바꾸십시오.
그리고 다음 코드가 작동합니다.
defmodule Secret do
def get_env(key, default \\ nil) do
Map.get(get_all_env(), key, default)
end
defp get_all_env() do
case :ets.whereis(__MODULE__) do
:undefined ->
:ets.new(__MODULE__, [:set, :public, :named_table])
{:ok, _} = Application.ensure_all_started(:hackney)
{:ok, _} = Application.ensure_all_started(:ex_aws)
env = fetch_env()
:ets.insert(__MODULE__, {:env, env})
env
ref ->
[{:env, env}] = :ets.lookup(ref, :env)
env
end
end
defp fetch_env() do
config = [
region: System.fetch_env!("AWS_REGION"),
access_key_id: System.fetch_env!("AWS_ACCESS_KEY_ID"),
secret_access_key: System.fetch_env!("AWS_SECRET_ACCESS_KEY")
]
get_parameters(config) |> Enum.into(%{})
end
defp get_parameters(config) do
# same as above
end
end
$ aws ssm put-parameter \
--name "/example/prod/DATABASE_URL" \
--value "ecto://postgres:postgres@localhost/example_prod" \
--type SecureString \
--overwrite
> Secret.get_env("DATABASE_URL")
"ecto://postgres:postgres@localhost/example_prod"
아직 이 접근 방식으로 전환하지는 않았지만 다음에 동일한 작업을 수행해야 할 때 고려할 것입니다.
Reference
이 문제에 관하여(Elixir 비밀에 대한 AWS SSM 파라미터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/aymanosman/aws-ssm-parameters-for-elixir-secrets-239g
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
config :my_app,
# when is this resolved?
database_url: System.get_env("DATABASE_URL")
config :my_app,
normal_var: "I am totally normal",
deferred_var: {:system, "SEE_YOU_LATER"}
def consume_config() do
case Application.get_env(:my_app, :deferred_var) do
{:system, var} -> System.get_env(var)
value -> value
end
end
config :my_app,
some_var: {:ssm, "THIS_LOOKS_FAMILIAR"}
먼저 필요한 종속성을 추가하고
Config.Provider
를 선언합니다.defmodule Example.MixProject do
def project do
[
...
releases: releases()
]
end
defp releases() do
[
example: [
config_providers: [
{Example.ConfigProvider, []}
]
]
]
end
defp deps do
[
...
{:ex_aws, "2.0"},
{:ex_aws_ssm, "2.0"}
]
end
end
그리고 아래와 같이 구현합니다.
defmodule Example.ConfigProvider do
@behaviour Config.Provider
@impl true
def init([]) do
[]
end
@impl true
def load(config, _state) do
{:ok, _} = Application.ensure_all_started(:hackney)
{:ok, _} = Application.ensure_all_started(:ex_aws)
params = get_parameters(config[:ex_aws]) |> Enum.into(%{})
Config.Reader.merge(config,
example: [
{ExampleWeb.Endpoint, secret_key_base: params["secret_key_base"]},
{Example.Repo, url: params["database_url"]}
]
)
end
defp get_parameters(config) do
ExAws.SSM.get_parameters_by_path(prefix(), with_decryption: true)
|> ExAws.request(config)
|> case do
{:ok, %{"Parameters" => params}} ->
params
|> Enum.map(fn param ->
{String.trim_leading(param["Name"], prefix()), param["Value"]}
end)
error ->
raise "Failed to fetch parameters: #{inspect(error)}"
end
end
defp prefix() do
"/example/prod/"
end
end
본질적으로 자리 표시자 값에 의존하는 제네릭
Config.Provider
을 사용하는 대신 원하는 구성을 추가하는 일회성Config.Provider
을 작성했습니다.잃어버린 것을 되찾는 것
이것은 내가 작업하고 있는 프로젝트에서 잘 작동했지만, 돌이켜보면 두 가지 문제가 있는 것 같습니다.
"잘못된"접근 방식에는 좋은 점이 있었습니다. 선언적이었고 구성이 모두 한 곳에 있었습니다.
나는 코드가 잃어버린 명확성을 되찾는 데 도움이 될 대안에 대해 생각했고 이것이 내가 생각해 낸 것입니다.
먼저 가능한 가장 간단한 API로 시작했습니다.
config :my_app,
some_var: System.get_env("SOME_VAR"),
database_url: Secret.get_env("DATABASE_URL")
System.get_env(...)
를 Secret.get_env(...)
로 바꾸십시오.
그리고 다음 코드가 작동합니다.
defmodule Secret do
def get_env(key, default \\ nil) do
Map.get(get_all_env(), key, default)
end
defp get_all_env() do
case :ets.whereis(__MODULE__) do
:undefined ->
:ets.new(__MODULE__, [:set, :public, :named_table])
{:ok, _} = Application.ensure_all_started(:hackney)
{:ok, _} = Application.ensure_all_started(:ex_aws)
env = fetch_env()
:ets.insert(__MODULE__, {:env, env})
env
ref ->
[{:env, env}] = :ets.lookup(ref, :env)
env
end
end
defp fetch_env() do
config = [
region: System.fetch_env!("AWS_REGION"),
access_key_id: System.fetch_env!("AWS_ACCESS_KEY_ID"),
secret_access_key: System.fetch_env!("AWS_SECRET_ACCESS_KEY")
]
get_parameters(config) |> Enum.into(%{})
end
defp get_parameters(config) do
# same as above
end
end
$ aws ssm put-parameter \
--name "/example/prod/DATABASE_URL" \
--value "ecto://postgres:postgres@localhost/example_prod" \
--type SecureString \
--overwrite
> Secret.get_env("DATABASE_URL")
"ecto://postgres:postgres@localhost/example_prod"
아직 이 접근 방식으로 전환하지는 않았지만 다음에 동일한 작업을 수행해야 할 때 고려할 것입니다.
Reference
이 문제에 관하여(Elixir 비밀에 대한 AWS SSM 파라미터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/aymanosman/aws-ssm-parameters-for-elixir-secrets-239g
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
config :my_app,
some_var: System.get_env("SOME_VAR"),
database_url: Secret.get_env("DATABASE_URL")
defmodule Secret do
def get_env(key, default \\ nil) do
Map.get(get_all_env(), key, default)
end
defp get_all_env() do
case :ets.whereis(__MODULE__) do
:undefined ->
:ets.new(__MODULE__, [:set, :public, :named_table])
{:ok, _} = Application.ensure_all_started(:hackney)
{:ok, _} = Application.ensure_all_started(:ex_aws)
env = fetch_env()
:ets.insert(__MODULE__, {:env, env})
env
ref ->
[{:env, env}] = :ets.lookup(ref, :env)
env
end
end
defp fetch_env() do
config = [
region: System.fetch_env!("AWS_REGION"),
access_key_id: System.fetch_env!("AWS_ACCESS_KEY_ID"),
secret_access_key: System.fetch_env!("AWS_SECRET_ACCESS_KEY")
]
get_parameters(config) |> Enum.into(%{})
end
defp get_parameters(config) do
# same as above
end
end
$ aws ssm put-parameter \
--name "/example/prod/DATABASE_URL" \
--value "ecto://postgres:postgres@localhost/example_prod" \
--type SecureString \
--overwrite
> Secret.get_env("DATABASE_URL")
"ecto://postgres:postgres@localhost/example_prod"
Reference
이 문제에 관하여(Elixir 비밀에 대한 AWS SSM 파라미터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/aymanosman/aws-ssm-parameters-for-elixir-secrets-239g텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)