Переменные окружения для начинающих разработчиков или использование .env файла в разработке программного обеспечения

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Что вас ожидает в этом руководстве

Безопасное управление конфиденциальными данными и настройками приложений может показаться сложной задачей для начинающих разработчиков. В этой статье мы разберем важные аспекты работы с переменными окружения, которые сделают вашу разработку более безопасной и эффективной.

Важно отметить, что рассмотренное решение не является лучшим способом для хранения секретных данных, однако, важность понимания принципов работы с переменными окружения сложно переоценить.

Начнем!

Что такое переменные окружения?

Переменные окружения — это значения, которые используются в различных командах и программных сценариях, выполняемых в операционной системе. Принципиально они работают точно так же, как переменные в языках программирования. Они представляют знакомые нам пары «ключ-значение» и используются для хранения параметров, настроек приложений, хранения ключей и других информационных данных.

Первый взгляд и практика

Давайте узнаем, какие переменные окружения уже есть в вашей операционной системе.

Примеры команд представлены для командной строки Windows и оболочки Unix (подобных) операционных систем отдельно.

CMD:

set

Bash:

printenv

Таким образом, вы увидите список переменных, которые уже существуют в окружении.

Взгляните внимательно на переменную окружения с именем PATH. Она имеет очень большое значение и содержит пути к директориям, содержащим исполняемые файлы программ. Когда мы обращаемся к различному программному обеспечению, используя его имя:

node main.js

Исполняемый файл с именем node (или node.exe для Windows) должен находиться в директориях, перечисленных в переменной окружения PATH. Если найти его не удастся, вы получите сообщение об ошибке:

command not found: node

или

"node" is not recognized as an internal or external command, operable program or batch file.

Если node.js уже установлен в операционной системе, но вы хотите ознакомиться с сообщением об ошибке из примера, используйте вместо node другой набор символов, который не будет соответствовать ни одному исполняемому файлу в директориях, перечисленных в PATH. Например, foobar или вовсе abracadabra123.

Если у вас уже установлена требуемая программа, но ее расположение отсутствует в переменной PATH, можно использовать полный путь к файлу в команде:

CMD:

"C:\Program Files\nodejs\node.exe" main.js

Bash:

# пример для nvm
/root/.nvm/versions/node/v16.18.0/bin/node main.js 

Напротив, если программа установлена и место ее расположения присутствует в переменной PATH, вы сможете узнать ее точное расположение следующим образом:

CMD:

where node

Bash:

echo $MSG

Создание, использование и удаление переменных окружения

Попробуем создать новую переменную:

CMD:

# Переменная доступна только для текущего сеанса командной строки
set MSG=hello

# Необходим перезапуск сессии командной строки
# Такая переменная останется доступной даже после перезапуска операционной системы 
setx MSG hello /M /D

Bash:

# Переменная доступна только для текущего сеанса терминала:
MSG=hello

# Необходим перезапуск сессии терминала,
# но переменная доступна для всех дочерних процессов 
export MSG=hello

# Чтобы сделать переменную доступной после перезагрузки операционной системы,
# необходимо добавить ее объявление в соответствующий файл конфигурации вашей оболочки
# .bashrc для Bash
echo 'export MSG=hello' >> ~/.bashrc
source ~/.bashrc

# .zshrc для Zsh
echo 'export MSG=hello' >> ~/.zshrc
source ~/.zshrc

Обратите внимание: так как переменные окружения являются константами, то общепринято писать их названия в верхнем регистре.

Пробуем использовать новую переменную:

CMD:

echo %MSG%

Bash:

echo $MSG

Теперь удаляем переменную:

CMD:

set MSG=
setx MSG ''

Bash:

unset MSG
# Также не забывайте удалить объявление переменной из файла
# конфигурации оболочки, если она была объявлена в нем. В противном
# случае, после перезапуска операционной системы переменная снова
# будет создана

Конфиденциальные данные в приложении

Наше программное обеспечение использует различного рода конфиденциальную информацию для полноценной работы. Такой информацией может оказаться API/SSH ключпароль для подключения к базе данных, ssl-сертификат или нечто похожее. Если мы расположим эти данные внутри нашего публичного хранилища исходного кода, произойдет их компрометация. Даже в случае, если хранилище приватное, расположение секретной информации означает, что все его коллабораторы или пользователи получают доступ к закрытой информации.

Однако мы можем избежать таких рисков, переместив секретную информацию за пределы хранилища и заменив ее ссылками на место, где она безопасно хранится. Такой подход обеспечивает высокий уровень безопасности, поскольку каждый пользователь будет иметь доступ только к собственному месту хранения конфиденциальных данных. Например, каждый пользователь может иметь свой пароль к локальной базе данных, и его ссылка будет указывать именно на личное хранилище с этим паролем.

Использование внешних хранилищ для секретных данных позволяет нам эффективно управлять доступом к этой информации и предотвратить несанкционированный доступ. Кроме того, это делает сотрудничество в команде более безопасным. Этот подход также облегчает ротацию ключей и паролей без необходимости изменения кода приложения, что повышает уровень защиты и снижает риски для безопасности данных.

Хранение секретных данных в переменных окружения

Рассмотрим в качестве хранилища секретных данных переменные окружения.

Давайте представим, что нашему приложению необходимо подключение к базе данных. В этом случае мы создадим несколько переменных среды, разместив в них необходимую информацию на сервере:

Сервер

echo 'export DB_HOST=srv_db_host' >> ~/.bashrc
echo 'export DB_PORT=srv_db_port' >> ~/.bashrc
echo 'export DB_NAME=srv_db_name' >> ~/.bashrc
echo 'export DB_USER=srv_db_user' >> ~/.bashrc
echo 'export DB_PASSWORD=srv_db_password' >> ~/.bashrc

source ~/.bashrc

Рабочее место разработчика

echo 'export DB_HOST=local_db_host' >> ~/.bashrc
echo 'export DB_PORT=local_db_port' >> ~/.bashrc
echo 'export DB_NAME=local_db_name' >> ~/.bashrc
echo 'export DB_USER=local_db_user' >> ~/.bashrc
echo 'export DB_PASSWORD=local_db_password' >> ~/.bashrc

source ~/.bashrc

Внимание! Располагать переменные окружения в файле bashrc без ограничения доступа к нему посторонним лицам неприемлемо, информация предоставлена только в демонстративных целях!

Теперь мы можем получить доступ к этим переменным внутри приложения:

Node.js

/*
process.env является глобальной переменной внутри node.jsприложения.
Она хранит в себе состояние всех переменных окружения ОС
на момент запуска приложения.
*/

const dbHost = process.env.DB_HOST;
const dbPort = process.env.DB_PORT;
const dbName = process.env.DB_NAME;
const dbUser = process.env.DB_USER;
const dbPassword = process.env.DB_PASSWORD;

Python

'''
В языке программирования python доступ к переменным окружения
возможно получить с использованием модуля OS. 
'''

import os

db_host = os.environ['DB_HOST']
db_port = os.environ['DB_PORT']
db_name = os.environ['DB_NAME']
db_user = os.environ['DB_USER']
db_password = os.environ['DB_PASSWORD']

Golang

/* 
в языке программирования Go доступ к переменным окружения осуществляется
c помощью пакета OS.
*/

package main

import (
	"os"
)

func main() {
	dbHost := os.Getenv("DB_HOST")
	dbPort := os.Getenv("DB_PORT")
	dbName := os.Getenv("DB_NAME")
	dbUser := os.Getenv("DB_USER")
	dbPassword := os.Getenv("DB_PASSWORD")
}

Использование файла .env для хранения переменных

Ранее мы рассмотрели, каким образом конфиденциальная информация может напрямую сохраняться в окружении операционной системы. Такой способ имеет некоторые недостатки. Эти переменные доступны не только для приложения.

Также есть некоторое неудобство их администрирования: они смешаны с переменными окружения, которые не нужны нашему приложению. Процесс замены значений переменных, в свою очередь, тоже не очень удобен.

Можем ли мы отделить необходимые переменные от остальных, сделать доступными только для приложения и управлять их состоянием удобным способом?
Да, мы можем воспользоваться практикой, ставшей золотым стандартом для решения этих проблем. Она заключается в использовании специальных библиотек, позволяющих при запуске приложения в его область видимости добавить ряд переменных, которые останутся недоступны другим процессам в операционной системе. Такие библиотеки присутствуют во всех популярных стеках разработки и используют в качестве хранилища специальный файл, оформленных строго определенным образом. Имя этого файла — .env (от англ. «environment»).

Синтаксис файла .env

Файл .env — это обычный текстовый файл без расширения с именем .env, каждая строка которого представляет собой пару ключ=значение. Вот пример записей переменных в такой файл:

DB_HOST=local_db_host
DB_PORT=local_db_port
DB_NAME=local_db_name
DB_USER=local_db_user
DB_PASSWORD=local_db_password

Давайте подключим этот файл в наше приложение, используя библиотеки, соответствующие необходимому стеку разработки:

Node.js:

/*
Установим библиотеку dotenv при помощи пакетного менеджера:
npm install dotenv
или
yarn add dotenv
*/

const dotenv = require('dotenv');
dotenv.config();

const dbHost = process.env.DB_HOST;
const dbPort = process.env.DB_PORT;
const dbName = process.env.DB_NAME;
const dbUser = process.env.DB_USER;
const dbPassword = process.env.DB_PASSWORD;

/* 
Объявленные переменные содержат соответствующие значения из .env файла.
Node.js версии 20 предоставляет экспериментальную поддержку .env файлов
без использования библиотеки "dotenv":
node --env-file=.env app.js
*/

Python:

# Установим пакет python-dotenv с помощью pip
# pip install python-dotenv

import os
from dotenv import load_dotenv

load_dotenv()

db_host = os.getenv("DB_HOST")
db_port = os.getenv("DB_PORT")
db_name = os.getenv("DB_NAME")
db_user = os.getenv("DB_USER")
db_password = os.getenv("DB_PASSWORD")

# Объявленные переменные содержат значения из .env файла и могут быть использованы

Golang:

/*
Установим пакет github.com/joho/godotenv с помощью go get
go get github.com/joho/godotenv
*/

package main

import (
	"github.com/joho/godotenv"
	"os"
)

func main() {
	err := godotenv.Load()

    if err != nil {
        log.Fatalf("Error loading .env file")
    }

	dbHost := os.Getenv("DB_HOST")
	dbPort := os.Getenv("DB_PORT")
	dbName := os.Getenv("DB_NAME")
	dbUser := os.Getenv("DB_USER")
	dbPassword := os.Getenv("DB_PASSWORD")

    // Объявленные переменные содержат значения из .env файла и могут быть использованы
}

ВНИМАНИЕ! Одна из важнейших целей использования .env в проекте — это отсутствие конфиденциальных данных в репозитории. Не забывайте позаботиться о добавлении .env в .gitignore, если вы используете git как систему контроля версий. Если используете альтернативную систему контроля версий, исключите .env в соответствии с технической документацией.

Разместите в .gitignore:

# Excluding the 
.env file.env

Такой подход хранения конфиденциальной информации можно наблюдать в большинстве крупных фреймворков или библиотек.

  • Laravel — один из наиболее популярных фреймворков для разработки веб-приложений на PHP. Файл .env в Laravel используется для хранения настроек базы данных, настроек приложения, секретных ключей, параметров электронной почты и других конфигурационных параметров. Laravel автоматически загружает переменные окружения из файла .env при запуске приложения.

  • Django — это фреймворк для разработки веб-приложений на Python. В проектах Django также распространено использование файла .env для хранения настроек базы данных, секретных ключей, настроек электронной почты и других конфигурационных параметров. Для загрузки переменных окружения из файла .env в Django обычно используется библиотека python-dotenv.

  • Ruby on Rails — фреймворк для разработки веб-приложений на Ruby. В проектах Ruby on Rails также популярно использование файла .env для хранения конфигурационных параметров, включая параметры базы данных, ключи API и другие настройки. Для загрузки переменных окружения из файла .env в Ruby on Rails обычно используется библиотека dotenv-rails.

На практике многие разработчики используют файл .env в своих проектах, чтобы легко настраивать и хранить параметры окружения и секретные данные без необходимости отображения их в коде.

.env.example

Правилами хорошего тона считается создание файла с именем .env.example, который должен хранить список необходимых для заполнения переменных. Этот файл используется для документирования и предоставления возможного примера заполнения значений переменных окружения. Обратите внимание, он может находиться в репозитории, но при этом не должен содержать настоящей конфиденциальной информации.

Заключение

В данной статье были рассмотрены важные аспекты обработки конфиденциальной информации в приложениях. Мы познакомились с наиболее распространенным способом сокрытия конфиденциальной информации из репозиториев программного обеспечения.

Давайте помнить, что безопасное обращение с конфиденциальными данными — это важный аспект разработки программного обеспечения. Использование файла .env в сочетании с грамотно организованными переменными окружения помогает обеспечить защиту информации и упрощает настройку приложений для различных окружений.

Спасибо за внимание!

Источник: https://habr.com/ru/companies/gnivc/articles/792082/


Интересные статьи

Интересные статьи

Эта статья продолжает часть I. Мы подробно рассмотрим систему модерации Midjourney, коснемся лимитов скорости (rate limits) Discord, двух самых сложных тем. В конце статьи приведен рабочий код.Прежде ...
Общепринятой лучшей практикой считается использование отключенных от сети корневых удостоверяющих центров, a.k.a., offline root CA. Кроме того, не рекомендуется хранить закрытый ключ в файле, потому, ...
Если вы регулярно читаете Хабр, то вам попадались статьи в духе: бросайте всё и начинайте изучать Swift, Kotlin или Flutter прямо сейчас. Давайте разбираться, правда ли с...
В этом статье я покажу, как для React-компонентов реализовать один из подходов на основе сущностей и их составляющих. Описываемый подход используется для решения той же п...
Представляю перевод статьи автора Evan Cameron, которая может помочь Java разработчикам лучше понять отличия и схожесть этих двух языков — оригинал на сайте автора. Не считая себя достаточно опыт...