Статья для участия в конкурсе Конкурс 2018 года - авторская статья по любой тематике нашего форума!
Добрый день уважаемые форумчане и коллеги по цеху!
С наступающим Вас Новым годом! Уже слышится звон бокалов, в голове )
Немного о себе:
Работаю главным инженером в сегменте среднего бизнеса, в Ставропольском крае.
И пожалуй как во многих компаниях нашей необъятной Родины на плечи инженеров ложится обязанность "здорового" функционирования серверной части ИТ инфраструктуры фирмы.
Одним из аспектов "здорового функционирования" этой самой инфраструктуры, является своевременное создание бэкапов, проверка работоспособности этих бэкапов, и сохранение их в целостности о чём собственно и пойдёт речь.
Проблема:
О шифровальщиках рассказывать никому не нужно, и потерях которые несет бизнес думаю тоже все в курсе, есть масса историй в сети и ежедневной практике.
Защитные средства, будь то антивирусные решения, крутые NG-шлюзы от топовых производителей не всегда способны своевременно распознать и блокировать как заражение так и сам процесс шифрования.
В случае заражения через эксплоиты нулевого дня - аля WannaCry, практически все защитные навороты оказались бесполезны, конечно ещё нужно обновляться своевременно, но это отдельная тема.
На самом деле именно после этой эпидемии захлестнувшей даже довольно крупных представителей бизнеса с мировым именем, мы с коллегами начали думать как защитить наши бэкапы (подразумевая, что избежать заражения практически невозможно), желательно что-бы решение работало в автоматическом режиме, и не нужно было ничего переключать ручками. Инженеры, чего с нас взять, ленивые по природе своей твари .
Решение:
Решение для нас, оказалось довольно простое, чем скорее всего нам и понравилось.
Для примера, можем взять следующий кейс: есть база данных, которая выгружается по определенному расписанию на внешнее сетевое хранилище.
Наша задача сделать так, чтобы это сетевое хранилище было не доступно в сети всё время, кроме того времени которое требуется для копирования базы. (К примеру у нас база весит 50Гб и копируется она 40-45 минут).
Т.е. автоматизировав данный процесс, мы получим 97% времени в сутки недоступный сетевой ресурс с "актуальной" базой данных (по состоянию на вчера) или другими данными, которые в случае заражения какой либо Ransom'варью она попросту не увидит и соответственно не зашифрует.
Код:
Обернуть код было решено в виндовую службу. Вот ссылка на шаблон:
Т.к. сервис будет критичный для нас, мы его будем мониторить через Zabbix (на предмет падения) и кстати через него же будем мониторить доступность порта на NAS'е. Если порт доступен, то это алярма, если нет то всё гуд.
0) Итак, секция USING
1) Метод OnStart запускает службу и необходимые для функционирования потоки.
2) Далее у нас метод в котором и производится вся нагрузка заложенная в службу.
Тут создаются папки для бэкапов, открывается порт на свитче Cisco, производится копирование с замером скорости, закрывается порт.
3) Отправка оповещения на почту
4) Следующие два метода получают файлы в заданной директории которые были создан сегодня. Запись в лог файл.
5) Метод подключение к свитчу, и выполнение действий с портом.
6) Методы копирования и замера скорости копирования. Взяты где-то на просторах сети, вроде codeproject, ссылку не смог найти.
7) Метод для присвоения имени папкам в зависимости от месяца.
Ну вот вроде и всё. Далее всё это дело компилируем, добавляем исполняемый файл в службы через PowerShell например:
Код конечно не изящный, но тут важна сама концепция, вы всегда можете допилить так как вам нужно.
Опционально добавляем сервер и NAS в систему мониторинга. Держим руку на пульсе.
Ещё раз всех с наступающим, желаю что-бы у вас всегда были бэкапы и не было факапов!
Добрый день уважаемые форумчане и коллеги по цеху!
С наступающим Вас Новым годом! Уже слышится звон бокалов, в голове )
Немного о себе:
Работаю главным инженером в сегменте среднего бизнеса, в Ставропольском крае.
И пожалуй как во многих компаниях нашей необъятной Родины на плечи инженеров ложится обязанность "здорового" функционирования серверной части ИТ инфраструктуры фирмы.
Одним из аспектов "здорового функционирования" этой самой инфраструктуры, является своевременное создание бэкапов, проверка работоспособности этих бэкапов, и сохранение их в целостности о чём собственно и пойдёт речь.
Проблема:
О шифровальщиках рассказывать никому не нужно, и потерях которые несет бизнес думаю тоже все в курсе, есть масса историй в сети и ежедневной практике.
Защитные средства, будь то антивирусные решения, крутые NG-шлюзы от топовых производителей не всегда способны своевременно распознать и блокировать как заражение так и сам процесс шифрования.
В случае заражения через эксплоиты нулевого дня - аля WannaCry, практически все защитные навороты оказались бесполезны, конечно ещё нужно обновляться своевременно, но это отдельная тема.
На самом деле именно после этой эпидемии захлестнувшей даже довольно крупных представителей бизнеса с мировым именем, мы с коллегами начали думать как защитить наши бэкапы (подразумевая, что избежать заражения практически невозможно), желательно что-бы решение работало в автоматическом режиме, и не нужно было ничего переключать ручками. Инженеры, чего с нас взять, ленивые по природе своей твари .
Решение:
Решение для нас, оказалось довольно простое, чем скорее всего нам и понравилось.
Для примера, можем взять следующий кейс: есть база данных, которая выгружается по определенному расписанию на внешнее сетевое хранилище.
Наша задача сделать так, чтобы это сетевое хранилище было не доступно в сети всё время, кроме того времени которое требуется для копирования базы. (К примеру у нас база весит 50Гб и копируется она 40-45 минут).
Т.е. автоматизировав данный процесс, мы получим 97% времени в сутки недоступный сетевой ресурс с "актуальной" базой данных (по состоянию на вчера) или другими данными, которые в случае заражения какой либо Ransom'варью она попросту не увидит и соответственно не зашифрует.
Код:
Обернуть код было решено в виндовую службу. Вот ссылка на шаблон:
Ссылка скрыта от гостей
Т.к. сервис будет критичный для нас, мы его будем мониторить через Zabbix (на предмет падения) и кстати через него же будем мониторить доступность порта на NAS'е. Если порт доступен, то это алярма, если нет то всё гуд.
0) Итак, секция USING
C#:
using System;
using System.ServiceProcess;
using System.Threading;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Net.Mail;
1) Метод OnStart запускает службу и необходимые для функционирования потоки.
C#:
protected override void OnStart(string[] args)
{
# Тушим порт на котором у нас NAS, вдруг он включен
DoCommand("shutdown", "interface GE 1/10");
# Пишем в логи, шлём письма
this.eventLog1.WriteEntry("BackupService is OnStart.");
SendMail("Служба BCP запущенна", "Служба BCP успешно запущенна");
WriteToLog("Служба BCP успешно запущенна" + DateTime.Now + "\n");
# Запускаем потоки на исполнение, один из которых делает бэкапы второй следит за статусом службы
ThreadPool.QueueUserWorkItem(new WaitCallback(ServiceBackupThread));
ThreadPool.QueueUserWorkItem(new WaitCallback(ServiceWorkerThread));
}
2) Далее у нас метод в котором и производится вся нагрузка заложенная в службу.
Тут создаются папки для бэкапов, открывается порт на свитче Cisco, производится копирование с замером скорости, закрывается порт.
C#:
private void ServiceBackupThread(object state)
{
while (!this.stopping)
{
int Errors = 0;
string files = "\n";
while (1 == 1)
{
# Исполнение задания в 3 утра по времени станции
if (DateTime.Now.Hour == 3 && DateTime.Now.Minute == 0)
{
# Тут у нас получение текущей даты и расположения бэкапов
string Year = DateTime.Now.Year.ToString();
string Month = GetMonth(DateTime.Now.Month.ToString());
string BCPath = "\\\\backups\\SQL\\";
string BCPath2 = "\\backups\\SQL\\";
# Создаём папки на NAS'е для бэкапов
try
{
Directory.CreateDirectory(BCPath2 + Year + "\\");
Directory.CreateDirectory(BCPath2 + Year + "\\" + Month + "\\");
}
catch(Exception ex)
{
WriteToLog("ОШИБКА: " + ex.Message + "\n");
}
WriteToLog("\n" + "НАЧАЛО РЕЗЕВНОГО КОПИРОВАНИЯ " + DateTime.Now + "\n");
try
{
DoCommand("no shutdown", "interface GE 1/10");
WriteToLog("ШАГ 1: Порт успешно открыт" + "\n");
}
catch (Exception ex)
{
WriteToLog("ОШИБКА НА ШАГЕ 1: " + ex.Message + "\n");
//SendMail("ОШИБКА НА ШАГЕ 1", "ОШИБКА НА ШАГЕ 1: " + ex.Message + "\n");
Errors++;
}
try
{
WriteToLog("ШАГ 2: Начало копированя файлов" + "\n");
List<FileInfo> FilesInNovember = GetFiles("D:\\backup\\SQL");
System.Collections.IList list = FilesInNovember;
for (int i = 0; i < list.Count; i++)
{
string file = list[i].ToString();
files = files + file + "\n";
string SoucePath = "D:\\backup\\SQL\\" + file;
string DestPath = BCPath + Year + "\\" + Month + "\\" + file;
WriteToLog("Copy file from " + SoucePath + " to " + DestPath + "\n");
MoveTime(SoucePath, DestPath);
}
WriteToLog("ШАГ 2: Файлы успешно скопированы" + "\n" + files);
}
catch (Exception ex)
{
WriteToLog("ОШИБКА НА ШАГЕ 2: " + ex.Message + "\n" + files);
//SendMail("ОШИБКА НА ШАГЕ 2", "ОШИБКА НА ШАГЕ 2: " + ex.Message + "\n");
Errors++;
}
try
{
DoCommand("shutdown", "interface GE 1/10");
WriteToLog("ШАГ 3: Порт успешно закрыт" + "\n");
}
catch (Exception ex)
{
WriteToLog("ОШИБКА НА ШАГЕ 3: " + ex.Message + "\n");
//SendMail("ОШИБКА НА ШАГЕ 3", "ОШИБКА НА ШАГЕ 3: " + ex.Message + "\n");
Errors++;
}
if (Errors == 0)
{
WriteToLog("РЕЗЕВНОЕ КОПИРОВАНИЕ ВЫПОЛНЕНО БЕЗ ОШИБОК " + DateTime.Now + "\n");
SendMail("РК ВЫПОЛНЕНО", "РЕЗЕРВНОЕ КОПИРОВАНИЕ ФАЙЛОВ " + files + " ВЫПОЛНЕНО БЕЗ ОШИБОК \n");
}
else
{
WriteToLog("РЕЗЕВНОЕ КОПИРОВАНИЕ ВЫПОЛНЕНО С " + Errors + " ОШИБКАМИ " + DateTime.Now + "\n");
SendMail("РК НЕ ВЫПОЛНЕНО", "РЕЗЕРВНОЕ КОПИРОВАНИЕ ВЫПОЛНЕНО С " + Errors + " ОШИБКАМИ \n" + files);
Errors = 0;
}
files = "\n";
}
Thread.Sleep(50000);
}
}
this.stoppedEvent.Set();
}
3) Отправка оповещения на почту
C#:
public static void SendMail(string Body, string Text)
{
try
{
MailMessage mail = new MailMessage("backups@company.ru", "youtname@company.ru");
SmtpClient client = new SmtpClient();
client.Port = 25;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Host = "mailserv.company.ru";
mail.Subject = Body;
mail.Body = Text;
client.Send(mail);
}
catch (Exception ex)
{
WriteToLog("ОШИБКА ОТПРАВКИ ПИСЬМА: " + "\n" + ex + "\n");
}
}
4) Следующие два метода получают файлы в заданной директории которые были создан сегодня. Запись в лог файл.
C#:
static private List<FileInfo> GetFiles(string directoryPath)
{
DirectoryInfo dir = new DirectoryInfo(directoryPath);
FileInfo[] theFiles = dir.GetFiles("*", SearchOption.TopDirectoryOnly);
return theFiles.Where(fl => fl.CreationTime.Date == DateTime.Today).ToList();
}
public static void WriteToLog(string Text)
{
StringBuilder sb = new StringBuilder();
sb.Append(Text);
File.AppendAllText("C:\\servicepath\\LogBackup.txt", sb.ToString());
sb.Clear();
}
5) Метод подключение к свитчу, и выполнение действий с портом.
C#:
public static void DoCommand(string Command, string Port)
{
TelnetConnection tc = new TelnetConnection("192.168.0.200", 23);
string s = tc.Login("cisco", "SuperSecretPASS", 1000);
Console.Write(s);
string prompt = s.TrimEnd();
prompt = "";
System.Threading.Thread.Sleep(1000);
prompt = "conf";
tc.WriteLine(prompt);
Console.Write(tc.Read());
System.Threading.Thread.Sleep(1000);
prompt = Port;
tc.WriteLine(prompt);
Console.Write(tc.Read());
System.Threading.Thread.Sleep(1000);
prompt = Command;
tc.WriteLine(prompt);
Console.Write(tc.Read());
System.Threading.Thread.Sleep(1000);
prompt = "end";
tc.WriteLine(prompt);
Console.Write(tc.Read());
System.Threading.Thread.Sleep(1000);
prompt = "write";
tc.WriteLine(prompt);
Console.Write(tc.Read());
System.Threading.Thread.Sleep(1000);
prompt = "Y";
tc.WriteLine(prompt);
Console.Write(tc.Read());
System.Threading.Thread.Sleep(1000);
prompt = "exit";
tc.WriteLine(prompt);
Console.Write(tc.Read());
System.Threading.Thread.Sleep(10000);
prompt = "";
tc.WriteLine(prompt);
Console.Write(tc.Read());
System.Threading.Thread.Sleep(10000);
prompt = "exit";
tc.WriteLine(prompt);
Console.Write(tc.Read());
Console.WriteLine("***DISCONNECTED" + "\n");
//WriteToLog("Command '" + Command + "' was executed for port: " + Port + "\n");
}
6) Методы копирования и замера скорости копирования. Взяты где-то на просторах сети, вроде codeproject, ссылку не смог найти.
C#:
public static void MoveTime(string source, string destination)
{
DateTime start_time = DateTime.Now;
FMove(source, destination);
long size = new FileInfo(destination).Length;
int milliseconds = 1 + (int)((DateTime.Now - start_time).TotalMilliseconds);
long tsize = size * 3600000 / milliseconds;
tsize = tsize / (int)Math.Pow(2, 30);
Console.WriteLine("Speed of copy " + tsize + "GB/hour" + "\n");
WriteToLog("Speed of copy " + tsize + "GB/hour" + "\n");
}
static void FMove(string source, string destination)
{
int array_length = (int)Math.Pow(2, 19);
byte[] dataArray = new byte[array_length];
using (FileStream fsread = new FileStream
(source, FileMode.Open, FileAccess.Read, FileShare.None, array_length))
{
using (BinaryReader bwread = new BinaryReader(fsread))
{
using (FileStream fswrite = new FileStream
(destination, FileMode.Create, FileAccess.Write, FileShare.None, array_length))
{
using (BinaryWriter bwwrite = new BinaryWriter(fswrite))
{
for (; ; )
{
int read = bwread.Read(dataArray, 0, array_length);
if (0 == read)
break;
bwwrite.Write(dataArray, 0, read);
}
}
}
}
}
}
7) Метод для присвоения имени папкам в зависимости от месяца.
C#:
public static string GetMonth(string Month)
{
if (Month == "1")
Month = "01 JAN";
if (Month == "2")
Month = "02 FEB";
if (Month == "3")
Month = "03 MRT";
if (Month == "4")
Month = "04 APR";
if (Month == "5")
Month = "05 MAY";
if (Month == "6")
Month = "06 JUNE";
if (Month == "7")
Month = "07 JULE";
if (Month == "8")
Month = "08 AUG";
if (Month == "9")
Month = "09 SEP";
if (Month == "10")
Month = "10 OKT";
if (Month == "11")
Month = "11 NOV";
if (Month == "12")
Month = "12 DEC";
return (Month);
}
Ну вот вроде и всё. Далее всё это дело компилируем, добавляем исполняемый файл в службы через PowerShell например:
C#:
if (Get-Service MoveBakups -ErrorAction SilentlyContinue) {
$service = Get-WmiObject -Class Win32_Service -Filter "name='MoveBakups'"
$service.StopService()
Start-Sleep -s 1
$service.delete()
}
$workdir = Split-Path $MyInvocation.MyCommand.Path
New-Service -name MoveBakups `
-displayName MoveBakups `
-binaryPathName "`"C:\servicepasth\MoveBakups.exe`""
Код конечно не изящный, но тут важна сама концепция, вы всегда можете допилить так как вам нужно.
Опционально добавляем сервер и NAS в систему мониторинга. Держим руку на пульсе.
Ещё раз всех с наступающим, желаю что-бы у вас всегда были бэкапы и не было факапов!