четверг, 30 декабря 2010 г.

Samba в Solaris 10: SMB-share for ZFS dataset

Около года назад мне на форуме задавали вопрос, как поднять SMB-шару на Solaris 9. На Solaris 9 эта задача не вполне тривиальна, а вот на Solaris 10 в текущих релизах - вполне себе решаемая.

Давайте посмотрим, как сделать аутентифицируемую доступную на запись сетевую шару для датасета ZFS на Solaris 10.

Прежде всего посмотрим, с каким релизом мы имеем дело:

root @ pegasus / # cat /etc/release
Oracle Solaris 10 9/10 s10x_u9wos_14a X86
Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
Assembled 11 August 2010

Очень хорошо, последний релиз. Теперь проверим наличие соответствующих пакетов:

root @ pegasus / # pkginfo|grep SUNWsmb
system SUNWsmbac samba - A Windows SMB/CIFS fileserver for UNIX (client)
system SUNWsmbar samba - A Windows SMB/CIFS fileserver for UNIX (Root)
system SUNWsmbau samba - A Windows SMB/CIFS fileserver for UNIX (Usr)

root @ pegasus / # pkginfo -l SUNWsmbac
PKGINST: SUNWsmbac
NAME: samba - A Windows SMB/CIFS fileserver for UNIX (client)
CATEGORY: system
ARCH: i386
VERSION: 11.10.0,REV=2005.01.08.01.09
BASEDIR: /
VENDOR: Sun Microsystems, Inc.
DESC: samba - A Windows SMB/CIFS fileserver for UNIX (client)
PSTAMP: sfw10-patch-x20100616080609
INSTDATE: Dec 27 2010 15:56
HOTLINE: Please contact your local service provider
STATUS: completely installed
FILES: 3 installed pathnames
3 shared pathnames
3 directories

Очень хорошо, пакеты стоят. Обратите внимание, что, во-первых, они устанавливаются по умолчанию в entire distribution (метакластер SUNWall), а во-вторых, это контрибьюторский софт, который не факт, что сохранится в составе системы после покупки Сана Ораклом.

Хорошо. Проверяем наличие сервиса Самбы и убеждаемся, что она управляется SMF (в текущем релизе Солярис):

root @ pegasus / # svcs samba
STATE STIME FMRI
disabled 16:52:56 svc:/network/samba:default

Конфигурационный пример лежит в директории /etc/sfw, и называется smb.conf-example:

root @ pegasus / # ls -al /etc/sfw
total 53
drwxr-xr-x 5 root bin 9 Dec 27 16:29 .
drwxr-xr-x 84 root sys 249 Dec 28 16:06 ..
-r--r--r-- 1 root bin 2561 Jan 8 2005 a2ps-site.cfg
-r--r--r-- 1 root bin 15250 Jan 8 2005 a2ps.cfg
drwxr-xr-x 4 root sys 5 Nov 30 16:02 openssl
dr-x------ 2 root bin 4 Dec 28 16:15 private
-r--r--r-- 1 root bin 9662 Jun 25 2010 smb.conf-example
drwxr-xr-x 2 root bin 10 Nov 30 16:15 zebra

Сделаем из него копию и отредактируем. Конфигурационный файл должен называться smb.conf. Отредактированный вариант простейшего сервера (для рабочей группы, без домена, с аутентификацией на нашем сервере) будет таким:

# This is the main Samba configuration file. You should read the
# smb.conf(5) manual page in order to understand the options listed
# here. Samba has a huge number of configurable options (perhaps too
# many!) most of which are not shown in this example
#
# For a step to step guide on installing, configuring and using samba,
# read the Samba-HOWTO-Collection. This may be obtained from:
# http://www.samba.org/samba/docs/Samba-HOWTO-Collection.pdf
#
# Many working examples of smb.conf files can be found in the
# Samba-Guide which is generated daily and can be downloaded from:
# http://www.samba.org/samba/docs/Samba-Guide.pdf
#
# Any line which starts with a ; (semi-colon) or a # (hash)
# is a comment and is ignored. In this example we will use a #
# for commentry and a ; for parts of the config file that you
# may wish to enable
#
# NOTE: Whenever you modify this file you should run the command "testparm"
# to check that you have not made any basic syntactic errors.
#
#======================= Global Settings =====================================
[global]

# workgroup = NT-Domain-Name or Workgroup-Name, eg: MIDEARTH
workgroup = WORKGROUP

# server string is the equivalent of the NT Description field
server string = Samba Server

# Security mode. Defines in which mode Samba will operate. Possible
# values are share, user, server, domain and ads. Most people will want
# user level security. See the Samba-HOWTO-Collection for details.
security = user

# This option is important for security. It allows you to restrict
# connections to machines which are on your local network. The
# following example restricts access to two C class networks and
# the "loopback" interface. For more examples of the syntax see
# the smb.conf man page
; hosts allow = 192.168.1. 192.168.2. 127.

# If you want to automatically load your printer list rather
# than setting them up individually then you'll need this
load printers = no

# you may wish to override the location of the printcap file
; printcap name = /etc/printcap

# on SystemV system setting printcap name to lpstat should allow
# you to automatically obtain a printer list from the SystemV spool
# system
; printcap name = lpstat

# It should not be necessary to specify the print system type unless
# it is non-standard. Currently supported print systems include:
# bsd, cups, sysv, plp, lprng, aix, hpux, qnx
; printing = cups

# Uncomment this if you want a guest account, you must add this to /etc/passwd
# otherwise the user "nobody" is used
; guest account = pcguest

# this tells Samba to use a separate log file for each machine
# that connects
log file = /var/samba/log/log.%m

# Put a capping on the size of the log files (in Kb).
max log size = 500

# Use password server option only with security = server
# The argument list may include:
# password server = My_PDC_Name [My_BDC_Name] [My_Next_BDC_Name]
# or to auto-locate the domain controller/s
# password server = *
; password server =

# Use the realm option only with security = ads
# Specifies the Active Directory realm the host is part of
; realm = MY_REALM

# Backend to store user information in. New installations should
# use either tdbsam or ldapsam. smbpasswd is available for backwards
# compatibility. tdbsam requires no further configuration.
; passdb backend = smbpasswd
passdb backend = tdbsam

# Using the following line enables you to customise your configuration
# on a per machine basis. The %m gets replaced with the netbios name
# of the machine that is connecting.
# Note: Consider carefully the location in the configuration file of
# this line. The included file is read at that point.
; include = /usr/sfw/lib/smb.conf.%m

# Configure Samba to use multiple interfaces
# If you have multiple network interfaces then you must list them
# here. See the man page for details.
; interfaces = 192.168.12.2/24 192.168.13.2/24

# Browser Control Options:
# set local master to no if you don't want Samba to become a master
# browser on your network. Otherwise the normal election rules apply
; local master = no

# OS Level determines the precedence of this server in master browser
# elections. The default value should be reasonable
; os level = 33

# Domain Master specifies Samba to be the Domain Master Browser. This
# allows Samba to collate browse lists between subnets. Don't use this
# if you already have a Windows NT domain controller doing this job
; domain master = yes

# Preferred Master causes Samba to force a local browser election on startup
# and gives it a slightly higher chance of winning the election
; preferred master = yes

# Enable this if you want Samba to be a domain logon server for
# Windows95 workstations.
; domain logons = yes

# if you enable domain logons then you may want a per-machine or
# per user logon script
# run a specific logon batch file per workstation (machine)
; logon script = %m.bat
# run a specific logon batch file per username
; logon script = %U.bat

# Where to store roving profiles (only for Win95 and WinNT)
# %L substitutes for this servers netbios name, %U is username
# You must uncomment the [Profiles] share below
; logon path = \\%L\Profiles\%U

# Windows Internet Name Serving Support Section:
# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
; wins support = yes

# WINS Server - Tells the NMBD components of Samba to be a WINS Client
# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
; wins server = w.x.y.z

# WINS Proxy - Tells Samba to answer name resolution queries on
# behalf of a non WINS capable client, for this to work there must be
# at least one WINS Server on the network. The default is NO.
; wins proxy = yes

# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
# via DNS nslookups. The default is NO.
dns proxy = no

# These scripts are used on a domain controller or stand-alone
# machine to add or delete corresponding unix accounts
; add user script = /usr/sbin/useradd %u
; add group script = /usr/sbin/groupadd %g
; add machine script = /usr/sbin/adduser -n -g machines -c Machine -d /dev/null -s /bin/false %u
; delete user script = /usr/sbin/userdel %u
; delete user from group script = /usr/sbin/deluser %u %g
; delete group script = /usr/sbin/groupdel %g


#============================ Share Definitions ==============================
[homes]
comment = Home Directories
browseable = no
writable = yes

# Un-comment the following and create the netlogon directory for Domain Logons
; [netlogon]
; comment = Network Logon Service
; path = /usr/sfw/lib/netlogon
; guest ok = yes
; writable = no
; share modes = no


# Un-comment the following to provide a specific roving profile share
# the default is to use the user's home directory
;[Profiles]
; path = /usr/local/samba/profiles
; browseable = no
; guest ok = yes


# NOTE: If you have a BSD-style print system there is no need to
# specifically define each individual printer
[printers]
comment = All Printers
path = /var/spool/samba
browseable = no
# Set public = yes to allow user 'guest account' to print
guest ok = no
writable = no
printable = yes

# This one is useful for people to share files
;[tmp]
; comment = Temporary file space
; path = /tmp
; read only = no
; public = yes

# A publicly accessible directory, but read only, except for people in
# the "staff" group
;[public]
; comment = Public Stuff
; path = /data/samba
; public = yes
; writable = no
; printable = no
; write list = @staff

# Other examples.
#
# A private printer, usable only by fred. Spool data will be placed in fred's
# home directory. Note that fred must have write access to the spool directory,
# wherever it is.
;[fredsprn]
; comment = Fred's Printer
; valid users = fred
; path = /homes/fred
; printer = freds_printer
; public = no
; writable = no
; printable = yes

# A private directory, usable only by fred. Note that fred requires write
# access to the directory.
;[fredsdir]
; comment = Fred's Service
; path = /usr/somewhere/private
; valid users = fred
; public = no
; writable = yes
; printable = no

# a service which has a different directory for each machine that connects
# this allows you to tailor configurations to incoming machines. You could
# also use the %U option to tailor it by user name.
# The %m gets replaced with the machine name that is connecting.
;[pchome]
; comment = PC Directories
; path = /usr/pc/%m
; public = no
; writable = yes

# A publicly accessible directory, read/write to all users. Note that all files
# created in the directory by users will be owned by the default user, so
# any user with access can delete any other user's files. Obviously this
# directory must be writable by the default user. Another user could of course
# be specified, in which case all files would be owned by that user instead.
;[public]
; path = /usr/somewhere/else/public
; public = yes
; only guest = yes
; writable = yes
; printable = no

# The following two entries demonstrate how to share a directory so that two
# users can place files there that will be owned by the specific users. In this
# setup, the directory should be writable by both users and should have the
# sticky bit set on it to prevent abuse. Obviously this could be extended to
# as many users as required.
;[myshare]
; comment = Mary's and Fred's stuff
; path = /usr/somewhere/shared
; valid users = mary fred
; public = no
; writable = yes
; printable = no
; create mask = 0765


[sambadir]
comment = Samba Service
path = /data/samba
valid users = samba
public = no
writable = yes
printable = no

Сохраним его и отложим пока запуск службы. Обратите внимание, что логи доступа будут писаться в /var/samba. И мы создаем единственную шару на точку монтирования /data/samba.

Создадим пользователя samba в операционной системе (так как мы не собираемся использовать AD для аутентификации):

root @ pegasus / # useradd -g staff -d /export/home/samba -m -s /bin/bash samba
64 blocks
root @ pegasus / # passwd samba
New Password:
Re-enter new Password:
passwd: password successfully changed for samba

Добавим его к базе паролей Самбы:

root @ pegasus / # smbpasswd -a samba
New SMB password:
Retype new SMB password:
Added user samba.

Создадим файловую систему (опираемся на первоисточник):

root @ pegasus / # zfs create -o casesensitivity=mixed -o nbmand=on data/samba
root @ pegasus / # zfs set recordsize=16k data/samba

И устанавливаем атрибут sharesmb в on:

root @ pegasus / # zfs set sharesmb=on data/samba

Кроме этого, необходимо дать права созданному пользователю samba на датасет:

root @ pegasus / # chown -R samba:staff /data/samba

Почти все. Теперь можно запустить сервис Самбы:

root @ pegasus / # svcadm enable samba
root @ pegasus / # svcs samba
STATE STIME FMRI
online 17:33:30 svc:/network/samba:default

и проверить логи демона:

root @ pegasus / # cat /var/samba/log/log.smbd

[2010/12/30 17:33:30, 0] smbd/server.c:(942)
smbd version 3.0.37 started.
Copyright Andrew Tridgell and the Samba Team 1992-2009

Все в порядке. Можно попробовать зайти с Windows-клиента с именем и паролем пользователя Самба:


среда, 29 декабря 2010 г.

Killer feature


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

Вот, например, выдержка из одного весьма уважаемого ресурса:

- А чем так хороша Solaris в сравнении с .... гм, другими ОС? Какая у нее killer feature, которой нет в других системах?
- А...гм, ну, эта... ZFS, DTrace.... ах, да - зоны!

Устриц не ел, но мнение имею.

Дорогие джентльмены. Надо лучше разбираться в предмете, о котором вы болтаете.

Первое и самое основное. Solaris - одна из самых высокопроизводительных и масштабируемых систем с полностью динамическим ядром на основе кода AT&T. Одна из первых систем, которая перешла на 64 разряда и при этом была исчерпывающе реализована в этом качестве - включая userland. Способная работать на реально больших боксах с сотнями процессоров. Причем была таковой еще задолго до того, как на что-то подобное стал способен, скажем, Линукс.

Второе. Задолго до появления любых промышленных реализаций виртуализации имела logical domains - технологию виртуализации инстансов операционной системы на больших SMP-машинах. Причем это было задолго до того, как тот же Линукс приообрел человеческие черты. Практически технология не имела и по сей день не имеет аналогов. Hot plug и мониторинг ооборудования тоже поддерживается с незапамятных времен.

Третье. Практически с самого начала имела в своем составе volume manager - чего многие системы в составе штатного operational environment не имеют по сей день, причем позволяла выполнять установку сразу на RAID.

Четвертое. Имеет и имела в своем составе JumpStart - блестящую технологию сетевой установки, включая установку через WAN, жалкое подобие левой руки которой появилось в Линуксе сравнительно недавно. То, что вы понятия не имеете, как ставить Solaris посредством JS - не означает, что этой технологии не существует. Более того, JS интегрирован в штатный процесс установки настолько, что позволяет выполнять пред- и постинсталляционные шаги по конфигурированию железа (например, созданию RAID и последующей установки на него) и самой системы (настройка, установка и развертывание ПО после установки) полностью автоматически. Kickstart - лишь бледный отголосок JumpStart. И существовала эта технология за много лет до того, как KS вообще оформился в виде идеи. Ни в одной системе не существует настолько мощного и гибкого механизма сетевой установки, как в Solaris.

Пятое. Содержит в своем составе ролевой механизм контроля доступа (RBAC), позволяющий системе в принципе обходиться без использования sudo - жалкого ублюдка из BSD-like систем. Кроме того, имеет мощный механизм trusted extensions, позволяющий расширять безопасность системы дл trusted-уровня легко и непринужденно. Поддерживает separation of duties и мандатный доступ. Легко доводится до уровня защиты B (и сертифицирована по этому уровню). Поддерживает FIPS-140 (разумеется). Поддерживает смарт-карты (тоже давным-давно).

Шестое. Имеет в своем составе SMF - механизм управления сервисами и их запуском, который только начали разрабатывать и встраивать в некоторых остальных UNIX-like системах. SMF использует XML для описания сервисов, основывается на SQLite БД и позволяет проделывать с сервисами все то, что с грехом пополам пытается разработать сообщество Линукс. Кроме того, имеет мощнейший механизм Fault Management, принципиально рассчитанный на работу в режиме 24x7x365. И о существовании которого многие так называемые сисадмины даже не догадываются.

Седьмое. ZFS - файловой системы с такими качественными и эксплуатационными характеристиками нет ни в одной другой ОС. Volume manager и файловая система в одном флаконе. Являющаяся частью системы. Позволяющая стартовать систему с нее. Безотказная и практически не фгарментируемая (повторяю для тех, кто на бронепоезде - ZFS является extent-based и не фрагментируется по определению). Это помимо штатной FS - JFS (начиная с релиза Солярис 9 4/04, до этого был UFS). А еще со снапшотов рута можно стартовать систему. Штатно. Ваша FS позволяет подобное проделывать? Кстати, поытайтесь разработать полную FS подобного уровня и за пяток лет довести ее до продуктива и промышленной пригодности.

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

Девятое. Имела и имеет совершенно блестящий стек TCP/IP. Да, он не позволяет сделать Solaris бриджом. Но позволял выполнять, например, link aggregation и multipathing давным-давно. Позволяет полностью изменить fingerprint системы до ее полной неузнаваемости. Полностью настраивается так, как и не снилось многим системам. Поддерживает роутинг BGP/OSPF. Поддерживает Jumbo Frames.

Десятое. Технологии кластеризации появились и поддерживаются в Солярис настолько давно, что были выбраны стандартом де-факто для Oracle RAC много лет назад. Да, это не технология штатного operational environment. Clusterware входил в состав JES - Java Enterprise System. А вам слабо?

Одиннадцатое. Технология Live Upgrade - это то, чего нет практически ни в одной ОС. Обновление системы в multi-user. На ZFS выглядящей особенно привлекательно, поскольку позволяет сделать апгрейд на тех же самых дисковых устройствах, где находится система. Включая платформу x86. Тоже реализовано давным давно. Полная замена ОС на всем скаку, с единственной перезагрузкой. С возможностью, в случае чего, откатиться к прежнему boot environment в одно действие. А ваша система так может?

Двенадцатое. Механизм flash-установки. С поддержкой ZFS. Нативно - как часть системы. Во многих системах есть имиджевание по-умолчанию? Позволяющее снять полный имидж рута на ходу, в multi-user?

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

Разумеется, поддерживается USB, iSCSI, IPSec, Kerberos - тоже достаточно давно. Практически как только появилась потребность - это было немедленно реализовано.

Я не то, чтобы хочу сказать, что всего этого нет в других системах. Дело в следующем, джентльмены. Солярис - промышленная ОС. Соответствующего уровня. И имела и имеет в своем составе все, что необходимо промышленной серверной ОС. Многих компонентов нет и не будет в современных самоделках.

Она способна работать на оборудовании, масштабов которого вы себе и вообразить не можете. Как насчет бокса на пару тысяч процессоров?

И - да, еще у нее были огромные жизненные циклы, до сих пор на ходу системы под Solaris 7 и 8. Причем посейчас система поддерживает все предыдущие архитектуры и компоненты оборудования, выпущенного более 10 лет назад. Это именно промышленная ОС, устанавливая которую, можно было не беспокоиться, что два-три года спустя ее обязательно придется обновлять или - упаси бог! - заменять. Это, согласитесь, совсем не заявление пингвинятников, что-де мы будем исключать поддержку старого оборудования из ядра.

Кстати, никакие подобные заявления не являются UNIX-way. Знаете, почему? Поддержка архитектур и железа в UNIX - это совсем немного ассемблерного кода. Который дистрибутив кардинально не увеличивает. Посмотрите на Солярис. Там это так. Весь platform-specific код не превышает размерами несколько сот мегабайт. Ах, у вас это не так? Так это уже ваши проблемы! Ах да, Linux is not UNIX... Он так, всего лишь жалкое подобие левой руки...

Лично мне, как эсплуатационнику, глубоко начхать, почему поддержка старого железа выводится из состава ОС. В промышленных системах, у которых жизненные циклы составляют десятки лет, никто не будет заменять работающий сервер возрастом 12 лет просто по причине несовместимости железа с новой версией ОС. Это вы у себя дома можете апгрейдить писюки хоть десять раз в год. Промышленные сервера эксплуатируются по принципу "Не сломалось - не чини". Поэтому лично мне важно, чтобы новые версии ОС заводились и работали на старом - по меркам писюшников - железе. (Я, кстати, сильно сомневаюсь, что Оракл будет и дальше поддерживать длительные жизненные циклы Солярис. Невыгодно. А бабло побеждает зло. Нет таких проблем, которые нельзя было бы решить с помощью бумажника).

Так что, мальчики и девочки, курите маны дальше. Всех killer features в Solaris вы не знаете и знать не будете.

Solaris реально был самой передовой ОС на планете. Жаль, что он попал в такие руки.

вторник, 21 декабря 2010 г.

Squid: Transparent proxy на Solaris 10

Однажды мне потребовалось построить прозрачный прокси (transparent proxy) на Solaris 10. Тщательное исследование Великой Сети показало, что подобного решения либо не существует, либо оно держится в большом секрете.

Поскольку готового решения (и даже направления поисков) не нашлось, пришлось проводить исследования самостоятельно.

Итак, задача.

Построить высоконадежный и эффективный полностью автономный (и необслуживаемый) прозрачный прокси-сервер на Solaris 10 с использованием ZFS и всех необходимых системных фишек.

В качестве прокси-сервера выберем Squid, как надежный и зарекомендовавший себя.

Установленная система предварительно тщательно минимизируется и харденится.

Для прозрачного режима прежде всего необходимо обеспечить перехват трафика HTTP (по 80 порту) непосредственно на самом прокси-сервере. Для этого необходима поддержка файрвола прокси-сервером в прозрачном режиме.

Небольшое исследование показало, что последние версии Squid не собираются с включением поддержки IPFilter.

Что ж, возьмем предсобранный Squid c Sunfereeware.

Прежде всего, однако, настроим IPFilter и TCP-стек.

Для корректного функционирования Сквида в прозрачном режиме необходимо включить IPv4-Forwarding:

root @ ktulhu /# routeadm -e ipv4-forwarding
root @ ktulhu /# routeadm -u

и настроить IPFilter:

root @ ktulhu /# cat /etc/ipnat.conf
rdr bge0 0.0.0.0/0 port 80 -> 0/32 port 3128


root @ ktulhu /# cat /etc/ipf.conf

# Block rules for RPC (open firewall)
block return-rst in quick on bge0 from any to any port=111
block return-rst in quick on bge0 from any to any port=6112

В /etc/defaultrouter самого прокси следует указать адрес маршрутизатора в Интернет.

Обратите внимание на правило редиректа IPFilter (Правила NAT/PAT IpFilter работают до выполнения набора основных правил) - оно должно быть написано именно таким образом, и на набор основных правил ipf.conf. Последние требуют некоторого пояснения.

Мы вынуждены использовать файрвол в открытом режиме (то есть блокировать только ненужные открытые порты), потому что в закрытом режиме через прокси не проходит аутентификация instant messengers - ICQ, MAgent, Jabber. Для установления обратной сессии при аутентификации им требуется открытый диапазон портов > 1024, который в нормальной конфигурации файрвола закрыт. Соответственно, мы закрываем только порты, которые обнаружили посредством NMap (их два) и которые мы хотим закрыть так, чтобы файрвола не было видно вообще. Для этого мы ставим опцию return-rst.

Замечание. Если вы выполнили минимизацию системных сервисов, больше никаких открытых портов, кроме порта Сквида, SSH и Apache не будет.

Следующим шагом создаем ZFS-пул data для кэша и логов и устанавливаем на нем recordsize равным 2048 байт (нам не нужны крупные экстенты, так как мы собираемся хранить много мелких файлов).

Хотя существует рекомендация использовать aufs для кэша Сквида на ZFS, с нашей версией (2.7) данная опция не работает. Впрочем, это не смертельно и Сквид прекрасно функционирует на ZFS (причем работает весьма быстро - ну-ка, кто там говорил, что ZFS - тормоз и фрагментируется? Extent-based файловые системы не фрагментируются по определению!).

Пишем базовую конфигурацию прокси.

#Recommended minimum configuration:
acl all src all
acl manager proto cache_object
acl localhost src 127.0.0.1/32
acl to_localhost dst 127.0.0.0/8
#
# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 10.0.0.0/8 # RFC1918 possible internal network
acl localnet src 172.16.0.0/12 # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network
#
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http

acl Safe_ports port 22 # SSH port
acl Safe_ports port 2222 # SSH alternate port

acl CONNECT method CONNECT

# TAG: http_access
# Allowing or Denying access based on defined access lists
#
# Access to the HTTP port:
# http_access allow|deny [!]aclname ...
#
# NOTE on default values:
#
# If there are no "access" lines present, the default is to deny
# the request.
#
# If none of the "access" lines cause a match, the default is the
# opposite of the last line in the list. If the last line was
# deny, the default is allow. Conversely, if the last line
# is allow, the default will be deny. For these reasons, it is a
# good idea to have an "deny all" or "allow all" entry at the end
# of your access lists to avoid potential confusion.
#
#Default:
# http_access deny all
#
#Recommended minimum configuration:
#
# Only allow cachemgr access from localhost
http_access allow manager localhost
http_access deny manager
# Deny requests to unknown ports
http_access deny !Safe_ports
# Deny CONNECT to other than SSL ports
http_access deny CONNECT !SSL_ports
#
# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on "localhost" is a local user
http_access deny to_localhost
#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS

# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
http_access allow localnet

# And finally deny all other access to this proxy
http_access deny all

# Squid normally listens to port 3128
http_port 3128 transparent

# TCP outgoing address
#tcp_outgoing_address 192.168.201.22

# Cache manager
cache_mgr admin@server.com

# We recommend you to use at least the following line.
hierarchy_stoplist cgi-bin ?

# Uncomment and adjust the following to add a disk cache directory.
#cache_dir ufs /usr/loal/squid/var/cache 100 16 256
cache_dir ufs /data/cache 32767 16 256

# Memory parameters
cache_mem 512 Mb
memory_pools off
maximum_object_size 8092 Kb

# Access log
access_log /data/cache/log/access.log squid

# Cache log
cache_log /data/cache/log/cache.log

# Store log
cache_store_log none

# Leave coredumps in the first cache dir
#coredump_dir /usr/local/squid/var/cache
coredump_dir /var/core

# Pid file
pid_filename /usr/local/squid/var/logs/squid.pid

# Add any of your own refresh_pattern entries above these.
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320

cache_effective_user squid
cache_effective_group squid

# SquidGuard rewriter
url_rewrite_program /usr/local/bin/squidGuard -c /usr/local/squidGuard/squidGuard.conf
url_rewrite_children 96
redirect_rewrites_host_header on
#redirector_bypass on

Из конфигурации следует, что мы используем под кэш датасет на созданном ZFS-пуле, выделяем достаточно большое количество памяти, и пропускаем весь трафик, так как фильтрацию контента мы будем выполнять посредством SquidGuard. Так же из конфигурации следует, что мы намереваемся кэшировать 32 Гб на диске (то есть технически наш прокси сможет обслуживать достаточно большую и активную сеть).

Так как мы намереваемся использовать достаточно большой кэш Сквида в памяти, имеет смысл ограничить ARC ZFS неким разумным значением, скажем, в 1/4 или 1/3 всей оперативной памяти:

root @ ktulhu /# cat /etc/system

set maxphys=1048576
set noexec_user_stack=1
set noexec_user_stack_log=1
set zfs:zfs_arc_max=1073741824
set rlim_fd_max=65536

Последний параметр необходим для повышения хардлимита на открытые файловые дескрипторы. По умолчанию значение параметра 256, что определенно мало для кэша (и это подтверждается запуском сквида под полной нагрузкой, в лог кэша сыплются ошибки о нехватке открытых файловых дескрипторов).

Дополнительно необходимо увеличить данный ограничитель пользователию squid вызовом ulimit в профиле:

root @ ktulhu / # cat /export/home/squid/.profile

MAIL=/usr/mail/${LOGNAME:?}

PATH=/usr/local/squid/sbin:/usr/local/ssl/bin:/usr/sfw/bin:/bin:/usr/bin:/usr/local/bin:/usr/ccs/bin:/usr/ucb
export PATH

ulimit -n 65536

Разумеется, после установки Сквида нужно обеспечить доступ ко всем необходимым директориям и файлам, выполнив, когда это необходимо, команды chown, предварительно создав непривилегированного пользователя squid и группу squid, от которых будет выполняться сам сквид, редиректор и Apache.

Следует также настроить resolver и запустить сервис dns/client (мы не будем поднимать автономный кэширующий DNS). В качестве серверов имен следует выбрать достаточно крупные и быстродействующие DNS-сервера. Я выбрал сервера OpenDNS.

На данном этапе следует закомментировать параметр url_rewrite_program.

Следующий шаг - это установка Apache (Apache 2) и SquidGuard. Веб-сервер нам потребуется для обслуживания редиректов SquidGuard, опциональной установки системы статистики и управления прокси-сервером (в данной статье не рассматривается).

Мы не будем мудрствовать и установим собранный Apache 2 с Sunfreeware.

После установки и предварительного конфигурирования Squid и Apache можно приступить к созданию структуры директорий кэша, проверке конфигураций и запуску. Убедившись, что все работает, можно создать SMF-сервисы для обеих служб (в данной статье не рассматривается; у автора написано готовое решение для указанных служб по созданию сервисов SMF в одно действие).

Следующим шагом установим и настроим SquidGuard.

Есть несколько неочевидных и неописанных тонкостей установки SquidGuard, не описанных по-сути нигде (я не нашел).

Во-первых, для установки SquidGuard потребуется Berkeley DB. После тщательного изучения руководств я выбрал версию 4.4.20 c Sunfreeware.

Во-вторых, перед сборкой необходимо установить в профиле пользователя squid (либо в глобальном профиле /etc/profile) переменную LD_LIBRARY_PATH:

root @ ktulhu /# export LD_LIBRARY_PATH=/usr/local/BerkeleyDB.4.4/lib:$LD_LIBRARY_PATH

иначе будут проблемы при сборке и последующей работе. Кроме того, при конфигурировании SquidGuard необходимо явно указывать пути к BerkeleyDB:

./configure --with-db=/usr/local/BerkeleyDB.4.4 --with-db-inc=/usr/local/BerkeleyDB.4.4/include --with-db-lib=/usr/local/BerkeleyDB.4.4/lib

В-третьих, SquidGuard не собирается Sun Studio, и необходимо использовать штатный GCC.

И в-четвертых, перед сборкой SquidGuard в Solaris требуется установить GNU M4 и библиотеку libsigsegv.

ВАЖНО. Последнее условие (зависимость именно от GNU M4) нигде не документировано, пришлось эту зависимость находить опытным путем.

Далее скачиваем нужные блэклисты, распаковываем их в /usr/local/squidGuard/db.

У себя я использую один из наиболее полных блэклистов.

Теперь (до компиляции баз) нужно написать конфигурацию SquidGuard. Для прозрачного прокси напишем относительно простую конфигурацию, которая будет резать наиболее ресурсоемкие или опасные сайты и рекламу:

#
# CONFIG FILE FOR SQUIDGUARD
#

dbhome /usr/local/squidGuard/db
logdir /usr/local/squidGuard/log

dest banners {
domainlist banners/domains
urllist banners/urls
expressionlist banners/expressions
redirect http://localhost/nobanner.gif
}

dest adv {
domainlist BL/adv/domains
urllist BL/adv/urls
redirect http://localhost/nobanner.gif
}

dest porn {
domainlist BL/porn/domains
urllist BL/porn/urls
}

dest sex {
domainlist BL/sex/education/domains
urllist BL/sex/education/urls
}

dest sex2 {
domainlist BL/sex/lingerie/domains
urllist BL/sex/lingerie/urls
}

dest spyware {
domainlist BL/spyware/domains
urllist BL/spyware/urls
}

dest redirector {
domainlist BL/redirector/domains
urllist BL/redirector/urls
}

dest dating {
domainlist BL/dating/domains
urllist BL/dating/urls
}

dest socialnet {
domainlist BL/socialnet/domains
urllist BL/socialnet/urls
}

acl {
default {
pass !banners !adv !porn !sex !sex2 !spyware !dating !socialnet !redirector all
redirect http://localhost/block.html
}
}

После этого можно скомпилировать базы. Убедитесь, что компиляция запускается от пользователя squid (ошибки permission denied являются наиболее распространенными при конфигурировании).

squid @ ktulhu ~$ squidGuard -C all

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

Будут скомпилированы базы, перечисленные в конфигурационном файле.

Убедимся, что все в порядке, права переданы - можно включить параметр url_rewrite_program в squid.conf и реконфигурировать сквид. После проверки лога cache.log, если все в порядке, все готово.

Замечание. Изменения конфигураций или баз данных SquidGuard требуют реконфигурации самого сквида.

Все?

Не совсем. Осталось немного. Мы хотим написать скрипт автоматического обновления баз SquidGuard раз в неделю (мы же создаем необслуживаемый сервер), и вызывать его из cron.

Что ж, напишем скрипт:

#!/sbin/sh

#
# SquidGuard blocklist update
#
# Written by Y.Voinov (C) 2010
#
# ident "@(#)update_blocklist.sh 1.1 10/12/21 YV"
#

#############
# Variables #
#############

# Modify PATH for SFW directory use
PATH=/usr/sfw/bin:$PATH

# List name
LIST_NAME="shallalist.tar.gz"

# Servers for downloading blacklist
SERVER1="http://www.shallalist.de/Downloads/$LIST_NAME"
SERVER2=""

SERVER_LIST="$SERVER1 $SERVER2"
TEMP_DIR="/tmp"

# Connection timeout for downloading
TIMEOUT=30

# Installation base dir
BASE="/usr/local"

# Base Squid installation directory
BASE_DIR="$BASE/squid"

# Base guard directory
BASE_DIR_GUARD="$BASE/squidGuard"

# Squid files paths
SQUID_PATH="$BASE_DIR""/sbin"
SQUID_CONF_PATH="$BASE_DIR""/etc"

# Squid files
SQUID_BIN_FILE="squid"
SQUID_CONF_FILE="squid.conf"

# Squid/SquidGuard user name
SQUID_USER="squid"

# SquidGuard location
SQUIDGUARD="$BASE/bin/squidGuard"

# OS utilities
CAT=`which cat`
CD=`which cd`
CUT=`which cut`
ECHO=`which echo`
GETENT=`which getent`
GZCAT=`which gzcat`
ID=`which id`
RM=`which rm`
SU=`which su`
GTAR=`which gtar`
UNAME=`which uname`
WGET=`which wget`

OS_VER=`$UNAME -r|$CUT -f2 -d"."`
OS_NAME=`$UNAME -s|$CUT -f1 -d" "`

###############
# Subroutines #
###############

os_check ()
{
if [ "$OS_NAME" != "SunOS" ]; then
$ECHO "ERROR: Unsupported OS $OS_NAME. Exiting..."
exit 1
elif [ "$OS_VER" -lt "10" ]; then
$ECHO "ERROR: Unsupported $OS_NAME version $OS_VER. Exiting..."
exit 1
fi
}

root_check ()
{
if [ ! `$ID | $CUT -f1 -d" "` = "uid=0(root)" ]; then
$ECHO "ERROR: You must be super-user to run this script."
exit 1
fi
}

checkuser ()
{
# Check squid user
username=$1
if [ ! -z "`$GETENT passwd $username`" ]; then
$ECHO "1"
else
$ECHO "0"
fi
}

checkconf ()
{
# Check Squid config file
config=$1
if [ -f "$SQUID_CONF_PATH"/"$config" ]; then
$ECHO "1"
else
$ECHO "0"
fi
}

download_list ()
{
# Get list from one server using server list
$ECHO "List downloading..."
for S in $SERVER_LIST; do
$SU - $SQUID_USER -c "$WGET -T $TIMEOUT -q -O $TEMP_DIR/$LIST_NAME $S"
retcode=`$ECHO $?`
case "$retcode" in
0)
$ECHO "List downloaded successfully."
break
;;
4)
$ECHO "Unable to resolve host address. Exiting..."
exit 4
;;
*)
$ECHO "Error downloading list from `$ECHO $S|$CUT -f1 -d '/'`. Try another server..."
continue
;;
esac
done

if [ "$retcode" != "0" ]; then
$ECHO "Error downloading list from all servers. Exiting..."
exit 1
fi
}

unpack_list ()
{
# Unpack list
$ECHO "List unpacking..."
$SU - $SQUID_USER -c "$GZCAT $TEMP_DIR/$LIST_NAME | $GTAR -x -C $BASE_DIR_GUARD/db"
}

list_compilation ()
{
# Call squidGuard DB recompilation
$ECHO "List compiling..."
$SU - $SQUID_USER -c "$SQUIDGUARD -C all"
}

reconfiguration ()
{
$ECHO "Reconfiguration..."
# Squid reconfiguration
program=$1
if [ "`checkconf $SQUID_CONF_FILE`" = "1" ]; then
if [ "`checkuser $SQUID_USER`" = "1" ]; then
$SU - $SQUID_USER -c "$SQUID_PATH/$program -k reconfigure"
else
$ECHO "ERROR: User $SQUID_USER not found."
$ECHO "Exiting..."
exit 2
fi
else
$ECHO "ERROR: Config file $SQUID_CONF_PATH/$SQUID_CONF_FILE not found."
$ECHO "Exiting..."
exit 2
fi
}

##############
# Main block #
##############

# OS check
os_check

# Root check
root_check

# Download list
download_list

# Unpack list
unpack_list

# Black list compilation
list_compilation

# Squid reconfiguration
reconfiguration $SQUID_BIN_FILE

exit 0

Помещаем скрипт в /usr/local/bin и создаем запись в /var/spool/cron/crontabs/root:

0 0 * * 6 [ -x /usr/local/bin/update_blocklist.sh ] && /usr/local/bin/update_blocklist.sh

Осталось рестартовать cron и готово:

root @ ktulhu /# svcadm restart cron

Все, наш сервер готов. Можно зайти на Зайцев.нет переполненный рекламой сайт и протестировать баннерорезку. :)

Финальный штрих - единственная настройка, которую надо сделать на клиентах - указать шлюзом по умолчанию адрес прокси.

PS. Ротация всех логов настраивается при помощи штатного для Solaris logadm. Если необходимо использовать SARG или другой счетчик статистики, следует убедиться, что график выполнения logadm не перекрывает график обновления статистики прокси. Разумеется, следует иметь в виду, что прозрачный прокси не позволяет использовать аутентификацию и статистика будет только по посещаемым сайтам и сетям, использующим проксирование.

пятница, 17 декабря 2010 г.

Облако без штанов 2: Насколько безопасна концепция SaaS/IaaS?

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

И вот почему.

Хотя некоторые джентльмены от маркетинга на содержании у вендоров и обвинили меня в рефлексии по поводу первой статьи на тему Cloud Computing, я еще даже не начинал критику.

Понять вендоров очень просто. Они хотят денег. Чем больше, тем лучше.

Однако, кроме соображений производительности итп. есть еще такое соображение, как безопасность.

Безопасность в последнее время повально игнорируется. Выпячивается удобство. Которое, в ряде случаев, оборачивается удобством односторонним. Чьим удобством? Этот вопрос совершенно риторический, если дать себе труд немного задуматься.

Итак, милая концепция IaaS. Инфраструктура как сервис. И SaaS. Программное обеспечение как сервис. Что с ними в действительности не так?

Не так вот что.

А что насчет "Ваши данные как сервис"?

Давайте вернемся к истокам. Основополагающей концепцией информационной безопасности является физическая безопасность.

Которая предполагает полный доступ к данным и информационным ресурсам, полный контроль над ними и возможность контроля физического доступа к ресурсам.

Я не случайно выделил все три пункта. Их выполнение возможно (при соблюдении ряда хорошо отработанных и известных принципов) в одном и только одном случае: ваша IT-инфраструктура находится под полным вашим контролем.

Да, собственная инфраструктура стоит денег. Да, вы можете сэкономить на IT-инфраструктуре, отдав ее на откуп провайдеру cloud computing. Однако вы, тем самым, фактически полностью выпускаете контроль над вашими данными из рук.

Полностью.

И еще.

Кто делает бэкап ваших данных в облаке? Провайдер? Размещая копии неведомо где и неведомо как? Вы готовы поверить на слово? Ах, вы сами делаете? А еще кто? Ах, да. Вы же этого не знаете, ваши данные и сервисы где-то там, далеко. Вы даже не видели, как выглядит ваша серверная ферма. Вы, кроме IP-адреса, вообще ничего о своей (своей?) инфраструктуре не знаете. Ладно, допустим, у вас небольшой веб-сервер, бэкап делается вами по сеточке - благо, каналы сейчас хорошие - и вы записываете его на флэшечку. А вы уверены, что больше никто не делает бэкапов ваших данных неведомо зачем неведомо куда? А если у вас терабайт в базе? Вы тоже сами резервируете его или это делает провайдер облачного сервиса?

Есть еще одно соображение. По-настоящему контролирует какой-либо ресурс тот, кто может его уничтожить. Вы можете уничтожить свой сервис в облаке, однако бэкапы вы не контролируете. Полностью контролирует и то и другое только провайдер.

Вы уверены, что в облаке все еще ВАШИ данные?

То, что этого не понимают (не хотят понимать) маркетологи - оставим на их совести. Понимать основополагающие концепции - не их работа.

Удивительно другое. Этого не понимают даже IT-специалисты.

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

(Кстати, о документах. У провайдеров CA - certification authority - есть в обязательном порядке документ, именуемый Certificate Policy Statement, в котором нам тоже предлагается поверить на слово, что при выпуске и отзыве сертификатов SSL выполняются определенные процедуры, что датацентры упомянутых CA обслуживаются и администрируются в соответствии с весьма жесткими политиками безопасности. Однако я никогда не слышал, чтобы упомянутые CA устраивали для сомневающихся экскурсии, позволяющие убедиться, что все так и есть, как написано в CPS. Да и, кроме того, как убедиться, что вам не показывают потемкинскую деревню? Это ведь совсем не то же самое, что пинком открыть дверь в собственную серверную и призвать к ответу собственного системного администратора. А, значит, все эти заявления в документах как ценные бумаги - по большей части не стоят и бумаги, на которой напечатаны. Все та же порочная концепция доверия третьим лицам. Хочешь, чтобы что-то было сделано хорошо - делай это сам.)

Горячий пример - WikiLeaks. Хотя основатель сервиса вроде бы как хакер (хакер?) и должен был понимать, что он на сайте совсем не комиксы размещает, однако умудриться засунуть свой сайт в публичное облако Amazon - это нечто. Стоило ли удивляться, что, когда по-настоящему запахло жареным, Amazon блокировал сервис по команде сверху и, разумеется, слил его данные куда следует?

Вы чувствуете, чем пахнет? Оруэлл вертится в гробу. Если цена вопроса будет достаточно высокой - все договорные обязательства, доверие (а что это такое? В безопасности нет такого понятия, как доверие. Есть знание.) - все идет в сад. Ваши данные извлекут, прошерстят, и каждый переданный в облако байт может быть использован против вас.

Ах, какие возможности для шантажа, рейдерства, политического давления!

Это стоит экономии средств?

Ах, да. У господ вендоров и их маркетологов есть на этот счет особое мнение. Вы можете использовать приватные облака. Фактически, свои собственные облачные инфраструктуры. "За ваши деньги - все, что угодно".

Однако - чем это отличается от наличия собственной IT-инфраструктуры классического типа?

А ничем. Кроме красивого и модного названия "cloud computing". Плюс полный набор затрат на оборудование, питание, охлаждение, администрирование...

How much is the fish, бабка?

Вряд ли приватное облако обойдется вам дешевле существующей сейчас инфраструктуры.

Что получается в сухом остатке? Единственное преимущество IaaS - экономия на инфраструктуре - становится иллюзорным, когда на другой чаше весов находится физический доступ к вашим данным. Приватное облако - не решение, а хитрый способ вынудить вас все равно оплатить из вашего кармана переоборудование бизнеса. Не мытьем, так катанием.

Примерно как на рынке PC вендроы вынуждают к непрерывным ежегодным апгрейдам. ROI/TCO уже никого не интересует. Нормальный бизнесмен, вложив деньги в оборудование, желает этому оборудованию многие лета, чтобы оно окупилось, причем, по-возможности, неоднократно.

А в нашем случае - вы в прошлом году приобрели новые сервера? Выкиньте их. И купите собственный датацентр для приватного облака, коль скоро вас так волнует безопасность. Ах, не волнует? Ну так спишите ваше новое оборудование и отдайте нам ваши данные. В облако. В наши руки. Под нашу ответственность.

Вернемся, однако, к проблемам безопасности.

Я предвижу возражение находчивых маркетологов - "Мы найдем и предложим техническое решение нетехнической проблемы! Например, давайте, мы зашифруем ваши данные в нашем облаке, так, что даже мы не сможем их расшифровать - ключ будет только у клиента!"

Это возражение не выдерживает никакой критики.

Первое. Вы, как клиент, вообще имеете понятие, какая программная платформа используется в облаке, в котором находится ваш сервис? Нет? Я так и думал. Вы этого не знаете. Обычно там используются открытые решения (в исходниках), которые допиливаются под себя. Кто, повторюсь - при достаточной цене вопроса - мешает провайдеру допилить алгоритмы шифрования или виртуализации для создания бэкдора?

Второе. Данные не могут быть зашифрованы постоянно. Для работы с ними их нужно расшифровать. Если я имею физический доступ к серверу, если я имею к нему привилегированный доступ - кто мешает мне просто получить доступ через /dev/kmem к расшифрованным данным в оперативной памяти? Да, технически можно осуществлять пошаговую расшифровку частей кода и данных непосредственно перед их выполнением или обработкой. Однако для этого нужно соответствующее ПО, которое даже сейчас проблематично во-первых, написать, а во-вторых - использовать в облаке. Ресурсов потребуется для работы такого софта очень нешуточно (а за них деньги платятся), а, кроме того, кто вам даст такой софт в облако засунуть? И, кстати - давно вы видели какую-нибудь Trusted OS или СУБД?

Третье. Закрытых систем, которые secure by design, в природе не существует. Точнее, они существуют. Но они сферические и находятся в вакууме. И они совершенно точно не используются в cloud computing.

Я немного слукавил. Такие системы существуют. Они находятся в бетонных бункерах под скалистыми горами, не подключены к интернету, и физически очень хорошо охраняются хозяином данных. Чувствуете, куда я клоню? Да, да - это именно то, от чего вас всеми силами пытаются отговорить. Потрясая призрачной экономией на собственной инфраструктуре.

Подведем итоги.

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

Если вы не размещаете ваших данных в публичном облаке по соображениям безопасности, а создаете собственное приватное облако - вы не экономите ни копейки, более того, облачная инфраструктура может обойтись значительно дороже классической. Хотя бы с учетом повышенной стоимости администрирования.

Вывод неутешителен. IaaS - мертвая концепция. На мой взгляд. Основополагающие принципы можно игнорировать (что может вам чрезвычайно дорого обойтись), но нельзя отбросить или перешагнуть.

PS. Даже сервис co-location уже не является безопасным. Сервер на co-location - уже не ваш собственный сервер и хранить на нем критические данные станет только полный недоумок. Это уже сервер провайдера. Он физически находится в руках у третьих лиц. Вот так, мальчики и девочки.

Solaris IPFilter: NAT/PAT

По неизвестной мне причине, Solaris IPFilter менее распространен и документирован, чем его родственники из BSD-like клонов. Некоторые вещи, достаточно обыденные в рядовом применении, не вполне очевидны и не вполне тривиальны. Причем гугл, как показывает практика, в данных исследованиях практически бесполезен.

Давайте попытаемся восполнить этот пробел.

Выполним одну простую задачу и посмотрим, что у нас получится.

Итак, у нас есть машина с настроенным IPFilter. Для примера возьмем порт 22 (SSH), используя NAT/PAT, перебросим его на порт 2222.

Стартовая конфигурация IPFilter (/etc/ipf.conf):

#
# ipf.conf
#
# IP Filter rules to be loaded during startup
#
# See ipf(4) manpage for more information on
# IP Filter rules syntax.

# Bastion host
#
# Host with one interface:
# eri0 - internal (blade)
#
# Rules by Y.Voinov (C) 2007,2010

# Rules groups setup
# Group 100 - Blocked networks & packets on any interface
# Group 100 setup
block in all head 100
# Group 200 - Opened incoming ports on eri0
# Group 200 setup
pass in on eri0 head 200

# ---------------------
# Common blocking rules
# ---------------------

# Block all IP fragments
block in quick all with frag group 100

# Block all short IP fragments
block in quick proto tcp all with short group 100

# Block any IP packets with options set in them
block in quick all with ipopts group 100

# Block OS fingerprint attempts
block in log first quick proto tcp all flags SF/SF group 100
block in log first quick proto tcp all flags SF/SFRA group 100
block in log first quick proto tcp all flags /SFRA group 100
block in log first quick proto tcp all flags SFUP/SFUP group 100
block in log first quick proto tcp all flags FUP/FUP group 100
block in log first quick proto tcp all flags F/F group 100
block in log first quick proto tcp all flags U/U group 100
block in log first quick proto tcp all flags P/P group 100

# Pass ICMP Echo
# ------------ eri0 interface ------------
#pass in quick on eri0 proto icmp from 192.168.0.0/24 to blade icmp-type echo keep state
#pass out quick on eri0 proto icmp from blade to 192.168.0.0/24 icmp-type echorep keep state
# ------------ eri0 interface ------------

# Stealth for traceroute (hide as hop)
# ------------ eri0 interface ------------
#block in quick on eri0 fastroute proto udp from any to any port 33434
>< 33465
# ------------ eri0 interface ------------

# Anti-spoofing rules
#block in quick from 192.168.0.0/16 to any group 100
block in quick from 172.16.0.0/12 to any group 100
block in quick from 10.0.0.0/8 to any group 100
block in quick from 127.0.0.0/8 to any group 100
block in quick from 0.0.0.0/8 to any group 100
block in quick from 169.254.0.0/16 to any group 100
block in quick from 192.0.2.0/24 to any group 100
block in quick from 204.152.64.0/23 to any group 100
block in quick from 224.0.0.0/3 to any group 100

# ------------ eri0 interface ------------
# 21 port - FTP service. Disable port and service on Internet servers!
#pass in quick on eri0 proto tcp from 192.168.100.0/24 to blade port=21 flags S keep state group 200
# 22 port - SSH
pass in quick on eri0 proto tcp from 192.168.100.0/24 to blade port=22 flags S keep state group 200
# 80 port - HTTP
pass in quick on eri0 proto tcp from 192.168.100.0/24 to blade port=80 flags S keep state group 200
# 177 port - x11 service. Disable port and service on Internet servers!
pass in quick on eri0 proto udp from 192.168.100.0/24 to blade port=177 keep state group 200
# 443 port - HTTPS
pass in quick on eri0 proto tcp from 192.168.100.0/24 to blade port=443 flags S keep state group 200
# 2222 port - SSH Alternative
#pass in quick on eri0 proto tcp from 192.168.100.0/24 to blade port=2222 flags S keep state group 200
# 1158 port - OEM console.
# Note: Secure console on Internet servers!
#pass in quick on eri0 proto tcp from 192.168.100.0/24 to blade port=1158 flags S keep state group 200
# Note: OEM console may be on port 5500
#pass in quick on eri0 proto tcp from 192.168.100.0/24 to blade port=5500 flags S keep state group 200
# 1521 port - Oracle. Disable port on Internet servers!
pass in quick on eri0 proto tcp from 192.168.100.0/24 to blade port=1521 flags S keep state group 200
# 7777 port - OHS. Disable port when using WebCache.
#pass in quick on eri0 proto tcp from any to blade port=7777 flags S keep state group 200
# 8888 port - OC4J main http port.
# Disable port after mount with mod_oc4j using AJP13.
#pass in quick on eri0 proto tcp from any to blade port=8888 flags S keep state group 200
# 9400 port - WebCache admin default port.
#pass in quick on eri0 proto tcp from any to blade port=9400 flags S keep state group 200
# ------------ eri0 interface ------------

# 53 port - DNS.
# ------------ eri0 interface ------------
# Allow incoming DNS requests to server
#pass in quick on eri0 proto tcp/udp from any to blade port=domain keep state group 200
# ------------ eri0 interface ------------

# 123 port - NTP.
# ------------ eri0 interface ------------
# Allow incoming NTP requests to server
#pass in quick on eri0 proto udp from any to blade port=ntp keep state group 200
# ------------ eri0 interface ------------

# Outgoing and callbacks sessions
# Allow connections originating from local machine out
pass out quick proto tcp/udp from any to any keep state keep frags
pass out quick proto icmp from any to any keep state

# Finally block all unmatched
block in quick all

Итак, порт 22 открыт. Напишем конфигурацию ipnat.conf:

rdr eri0 0.0.0.0/0 port 2222 -
> 0/32 port 22

Некоторые пояснения к правилу. Слева написан адрес 0.0.0.0/0, что означает любой адрес. Мы можем с таким же успехом (и в нашем случае это будет более правильно) написать 192.168.0.0/16, однако мы хотели получить наиболее общее правило, которое не требуется менять в случае изменения адресов сетей; кроме того, ограничения доступа из сетей и адресов энфорсятся в нашем случае правилами ipf.conf. Адрес 0/32 справа не ошибка. Он означает - "использовать адрес, назначенный интерфейсу". Конечно, там можно попытаться написать и 127.0.0.1, однако тогда редирект не будет работать.

Обратите внимание: правила ipnat.conf применяются в порядке написания (так же, как и правила ipf.conf) и выполняются ДО применения правил ipf.conf.

Перезапустим IPFilter и проверим состояние наших правил:

root @ blade / # ipnat -l
List of active MAP/Redirect filters:
rdr eri0 0.0.0.0/0 port 2222 -
> 0.0.0.0/32 port 22 tcp

List of active sessions:
RDR 192.168.100.5 22
<- -> 192.168.100.5 2222 [192.168.100.1 2510]
RDR 192.168.100.5 22
<- -> 192.168.100.5 2222 [192.168.100.1 2506]

Редирект работает, соединения устанавливаются.

Еще раз обратите внимание на конфигурацию ipf.conf. Порт 2222 в основной конфигурации закрыт. Поскольку правила NAT выполняются до основных правил фильтра, наше правило PAT создает еще один открытый порт 2222 и редиректит его на открытый порт 22. Причем порт 22 тоже открыт, с ним можно соединиться.

Это можно проверить сканером портов:

Starting Nmap 5.21 ( http://nmap.org ) at 2010-12-17 15:35 Центральная Азия (зима)
NSE: Loaded 36 scripts for scanning.
Initiating ARP Ping Scan at 15:36
Scanning blade (192.168.100.5) [1 port]
Completed ARP Ping Scan at 15:36, 0.49s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 15:36
Scanning blade (192.168.100.5) [1000 ports]
Discovered open port 22/tcp on 192.168.100.5
Discovered open port 2222/tcp on 192.168.100.5
Completed SYN Stealth Scan at 15:36, 5.45s elapsed (1000 total ports)
Initiating Service scan at 15:36
Scanning 2 services on blade (192.168.100.5)
Completed Service scan at 15:36, 0.22s elapsed (2 services on 1 host)
Initiating OS detection (try #1) against blade (192.168.100.5)
Retrying OS detection (try #2) against blade (192.168.100.5)
NSE: Script scanning 192.168.100.5.
NSE: Starting runlevel 1 (of 1) scan.
Initiating NSE at 15:36
Completed NSE at 15:36, 1.28s elapsed
NSE: Script Scanning completed.

Nmap scan report for blade (192.168.100.5)
Host is up (0.0024s latency).
Not shown: 995 filtered ports

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 5.6p1-hpn13v10 (protocol 2.0)
| ssh-hostkey: 1024 72:8e:3f:d4:91:77:85:39:2a:71:f1:a5:13:b1:62:c1 (DSA)
|_2048 57:b7:86:57:0c:c7:9b:cd:b6:90:e4:e8:18:0b:c0:c6 (RSA)
80/tcp closed http
443/tcp closed https
1521/tcp closed oracle
2222/tcp open ssh OpenSSH 5.6p1-hpn13v10 (protocol 2.0)
| ssh-hostkey: 1024 72:8e:3f:d4:91:77:85:39:2a:71:f1:a5:13:b1:62:c1 (DSA)
|_2048 57:b7:86:57:0c:c7:9b:cd:b6:90:e4:e8:18:0b:c0:c6 (RSA)

MAC Address: 00:03:BA:10:D0:86 (Sun Microsystems)

OS fingerprint not ideal because: Didn't receive UDP response. Please try again with -sSU
No OS matches for host
Uptime guess: 0.098 days (since Fri Dec 17 13:14:53 2010)
Network Distance: 1 hop
TCP Sequence Prediction: Difficulty=258 (Good luck!)
IP ID Sequence Generation: Incremental

HOP RTT ADDRESS
1 2.35 ms blade (192.168.100.5)

Read data files from: H:\Program Files\Nmap

OS and Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .

Nmap done: 1 IP address (1 host up) scanned in 20.42 seconds
Raw packets sent: 2079 (96.514KB) | Rcvd: 25 (1306B)

Как видно, редирект нашего порта выглядит как еще один открытый порт.

Разумеется, данный пример совершенно абстрактен. Более политкорректно и правильно перебросить SSH прямо на порт 2222 настройками конфигурации сервиса :). Однако мы выбрали данный пример не для практических целей, а дабы убедиться в порядке применения правил IPFilter.

PS. Правила редиректа портов по такому принципу можно использовать при реализации прозрачных прокси с использованием, например, сервера Squid. Я напишу об этом более подробно в одной из следующих статей.

среда, 8 декабря 2010 г.

Зоны Solaris VI: Перемещение зон

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

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

Давайте посмотрим, как это делается, на практике.

Перемещение зоны в другую файловую систему, в том числе на другой хост

Итак, у нас есть две неглобальных зоны, одну из которых мы хотели бы переместить:

root @ pegasus / # zoneadm list -vc
ID NAME STATUS PATH BRAND IP
0 global running / native shared
1 zone2 running /data/zone2 native shared
2 zone1 running /data/zone1 native shared
root @ pegasus / # zoneadm -z zone2 detach
zoneadm: zone 'zone2': detach operation is invalid for running zones.

Упс, работающая зона не может быть отсоединена. Как и было сказано. Остановим ее и выполним detach:

root @ pegasus / # zoneadm -z zone2 halt
root @ pegasus / # zoneadm -z zone2 detach

Давайте для начала переместим зону в другой датасет на том же самом хосте. Сначала переместим сам датасет средствами zfs rename:

root @ pegasus / # zfs rename data/zone2 data/zones/zone2
cannot create 'data/zones/zone2': parent does not exist
root @ pegasus / # zfs create data/zones
root @ pegasus / # zfs rename data/zone2 data/zones/zone2

Готово. Датасет перемещен. Осталось поменять параметр zonepath перенесенной зоны и можно ее стартовать:

root @ pegasus / # zoneadm list -vc
ID NAME STATUS PATH BRAND IP
0 global running / native shared
2 zone1 running /data/zone1 native shared
- zone2 configured /data/zone2 native shared

root @ pegasus / # zonecfg -z zone2 set zonepath=/data/zones/zone2
root @ pegasus / # zoneadm -z zone2 attach
zoneadm: /data/zones/zone2: No such file or directory
could not verify zonepath /data/zones/zone2 because of the above errors.
zoneadm: zone zone2 failed to verify

Нет, стартовать еще нельзя. Почему?

Потому что точка монтирования нового датасета осталась прежней. Изменим ее:

root @ pegasus / # zfs list
NAME USED AVAIL REFER MOUNTPOINT
data 11.0G 8.61G 41K /data
data/zone1 313M 1.69G 313M /data/zone1
data/zones 3.37G 8.61G 21K /data/zones
data/zones/zone2 3.37G 642M 3.37G /data/zone2

root @ pegasus / # zfs set mountpoint=/data/zones/zone2 data/zones/zone2
root @ pegasus / # zoneadm -z zone2 attach
root @ pegasus / # zoneadm -z zone2 boot

Порядок. Внутри хоста зону перенесли в другой датасет.

Просто для очистки совести перенесем и вторую зону в тот же самый датасет:

root @ pegasus / # zoneadm -z zone1 halt
root @ pegasus / # zoneadm -z zone1 detach
root @ pegasus / # zfs rename data/zone1 data/zones/zone1
root @ pegasus / # zfs set mountpoint=/data/zones/zone1 data/zones/zone1
root @ pegasus / # zonecfg -z zone1 set zonepath=/data/zones/zone1
root @ pegasus / # zoneadm -z zone1 attach
root @ pegasus / # zoneadm list -vc
ID NAME STATUS PATH BRAND IP
0 global running / native shared
- zone1 installed /data/zones/zone1 native shared
- zone2 installed /data/zones/zone2 native shared
root @ pegasus / # zoneadm -z zone1 boot
root @ pegasus / # zoneadm -z zone2 boot
root @ pegasus / # zoneadm list -vc
ID NAME STATUS PATH BRAND IP
0 global running / native shared
9 zone1 running /data/zones/zone1 native shared
10 zone2 running /data/zones/zone2 native shared

Если необходимо перенести зону на другой хост, то процедура лишь немного сложней. Собственно датасет (датасеты) зоны передаются на другой хост командами zfs send/zfs receive. После передачи датасета на новом хосте необходимо создать конфигурацию зоны из перенесенных данных командой zonecfg create -a:

zonecfg:zone1
> create -a /data/zones/zone2

после чего можно просмотреть и изменить конфигурацию командой zonecfg:

root @ pegasus / # zonecfg -z zone2 set zonepath=/data/zones/zone2
root @ pegasus / # zoneadm -z zone2 attach

Кроме zonepath в конфигурации может потребоваться изменить группу параметров net - address и physical, а также можно поменять и другие конфигурационные параметры. Ресурсные ограничения, если они уже присутствуют на новом хосте, могут привести к ругани при конфигурировании перенесенной зоны, однако конфигурация создается и ресурсные лимиты включаются в определение зоны.

Далее, после корректировки конфигурации зоны, выполняется команда zoneadm attach, и после этого можно стартовать перенесенную зону.

Простое перемещение зоны в пределах хоста

На самом деле для перемещения зоны в пределах хоста есть более короткий путь, чем attach/detach. Переместим зону zone2 снова в прежнее местоположение:

root @ pegasus / # zoneadm -z zone2 halt
root @ pegasus / # zoneadm -z zone2 move /data/zone2
root @ pegasus / # zoneadm list -vc
ID NAME STATUS PATH BRAND IP
0 global running / native shared
9 zone1 running /data/zones/zone1 native shared
- zone2 installed /data/zone2 native shared
root @ pegasus / # zoneadm -z zone2 boot
root @ pegasus / # zfs list
NAME USED AVAIL REFER MOUNTPOINT
data 11.0G 8.61G 36K /data
data/zones 3.68G 8.61G 23K /data/zones
data/zones/zone1 313M 1.69G 313M /data/zones/zone1
data/zones/zone2 3.37G 644M 3.37G /data/zone2

Упс! Поменялась точка монтирования, но не датасет.

Пробуем переместить датасет:

root @ pegasus / # zfs rename data/zones/zone2 data/zone2
cannot unmount '/data/zone2': Device busy

Упс! Низ-зя. Зона работает, датасет занят. Остановим зону и повторим переименование:

root @ pegasus / # zoneadm -z zone2 halt
root @ pegasus / # zfs rename data/zones/zone2 data/zone2

root @ pegasus / # zfs list
NAME USED AVAIL REFER MOUNTPOINT
data 11.0G 8.61G 36K /data
data/zone2 3.37G 644M 3.37G /data/zone2
data/zones 313M 8.61G 23K /data/zones
data/zones/zone1 313M 1.69G 313M /data/zones/zone1
root @ pegasus / # zoneadm list -vc
ID NAME STATUS PATH BRAND IP
0 global running / native shared
9 zone1 running /data/zones/zone1 native shared
- zone2 installed /data/zone2 native shared
root @ pegasus / # zoneadm -z zone2 boot
root @ pegasus / # zoneadm list -vc
ID NAME STATUS PATH BRAND IP
0 global running / native shared
9 zone1 running /data/zones/zone1 native shared
12 zone2 running /data/zone2 native shared

Вот теперь все правильно. Зона перемещена в другой датасет на том же самом хосте.

пятница, 3 декабря 2010 г.

Зоны Solaris V: Конфигуратор зон

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

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

Что ж, давайте потратим время и напишем инструмент для конфигурирования, установки и назначения дисковых квот зонам Solaris.

Мы воспользуемся тем фактом, что зоны конфигурировать можно не только интерактивно, но и при помощи однострочников команды zonecfg.

Итак, собственно

конфигурационный скрипт:
____________________

#!/sbin/sh

#
# Solaris Zones configurator/install tool.
#
# ident "@(#)zoneinst.sh 1.0 11/24/10 YV"
#
# Copyright (C) 2010, Y.Voinov
#

#############
# Variables #
#############

# OS variables
CUT=`which cut`
ECHO=`which echo`
EXPR=`which expr`
GETOPT=`which getopt`
GREP=`which grep`
ID=`which id`
SED=`which sed`
UNAME=`which uname`
ZONEADM=`which zoneadm`
ZONECFG=`which zonecfg`
ZFS=`which zfs`

OS_VER=`$UNAME -r|$CUT -f2 -d"."`
OS_NAME=`$UNAME -s|$CUT -f1 -d" "`

###############
# Subroutines #
###############

os_check ()
{
if [ "$OS_NAME" != "SunOS" ]; then
$ECHO "ERROR: Unsupported OS $OS_NAME. Exiting..."
exit 1
elif [ "$OS_VER" -lt "10" ]; then
$ECHO "ERROR: Unsupported $OS_NAME version $OS_VER. Exiting..."
exit 1
fi
}

root_check ()
{
if [ ! `$ID | $CUT -f1 -d" "` = "uid=0(root)" ]; then
$ECHO "ERROR: You must be super-user to run this script."
exit 1
fi
}

usage ()
{
# Print usage note
$ECHO "Usage: $0 [-i] [-n] [-s] [-h] zoneX.cfg"
$ECHO "Where zoneX.cfg is zone parameters file (required)."
$ECHO "-i option prints zone info when configuration complete (optional)."
$ECHO "-n option uses for non-interactive zone installation and quota assigning (optional)."
$ECHO "-s options skips zone installation and quota assigning."
$ECHO "-h prints this note."
exit 0
}

get_cfg_file ()
{
par=$1

if [ "x$par" = "x" ]; then
$ECHO "ERROR: Config file not found."
$ECHO "Exiting..."
exit 1
else
# Source config file
. $par
fi
}

check_zone_name ()
{
# Check is zone $ZONE already exists
zone="`$ZONEADM list|$GREP $ZONE`"
if [ "$zone" != "" ]; then
$ECHO "ERROR: Zone $ZONE already exists! Exiting..."
exit 1
fi
}

common_zone_cfg ()
{
# Common zone configuration routine
dedicated=$1

if [ "$dedicated" = "0" ]; then
$ZONECFG -z $ZONE "set scheduling-class=$SCHEDCLASS; set cpu-shares=$CPU;"
if [ "x$CAPPED_CPU" != "x" ]; then
# Set capped CPU if specified
$ZONECFG -z $ZONE "add capped-cpu; set ncpus=$CAPPED_CPU; end;"
fi
elif [ "$dedicated" = "1" ]; then
# Set dedicated CPU if specified
$ZONECFG -z $ZONE "add dedicated-cpu; set ncpus=$NCPU; set importance=$IMPORTANCE; end;"
else
$ECHO "ERROR: Unknown value DEDUCATED_CPU. Exiting..."
exit 1
fi
# Set capped memory if parameter specified
if [ "$CAPPED_MEM" = "1" -a ! -z "$MPHYS" -a ! -z "$MSWAP" -a ! -z "$MLOCK" ]; then
$ZONECFG -z $ZONE "add capped-memory; set physical=$MPHYS; set swap=$MSWAP; set locked=$MLOCK; end;"
fi
# Set zone filesystem parameters
$ZONECFG -z $ZONE "add fs; set dir=$FS; set special=$SPEC; set type=lofs; set options=ro; end;"
# Set IP type for zone. Default is shared (when not specified IP type).
if [ "x$IP_TYPE" != "x" -a "$IP_TYPE" = "exclusive" ]; then
$ZONECFG -z $ZONE "set ip-type=exclusive"
$ZONECFG -z $ZONE "add net; set physical=$PHYS; end;"
else
# Set zone network parameters
if [ "x$DEFROUTER" != "x" ]; then
$ZONECFG -z $ZONE "add net; set address=$ADDR; set physical=$PHYS; set defrouter=$DEFROUTER; end;"
else
$ZONECFG -z $ZONE "add net; set address=$ADDR; set physical=$PHYS; end;"
fi
fi
}

sparse_root_zone ()
{
# Create sparce root zone
$ZONECFG -z $ZONE "create; set autoboot=true; set zonepath=$ZONEPATH;"
$ZONECFG -z $ZONE "add inherit-pkg-dir; set dir=$IPD; end;"
# Add most common zone configuration
common_zone_cfg $DEDICATED_CPU
}

whole_root_zone ()
{
# Create whole root zone
$ZONECFG -z $ZONE "create -b; set autoboot=true; set zonepath=$ZONEPATH;"
# Add most common zone configuration
common_zone_cfg $DEDICATED_CPU
}

install_configured_zone ()
{
$ZONEADM -z $ZONE install
retcode=`$ECHO $?`
case "$retcode" in
0) $ECHO "*** Zone $ZONE installation successful";;
*) $ECHO "*** Zone $ZONE installation has errors. Exiting..."
exit
;;
esac
}

set_disk_quota ()
{
# Get zone dataset from mountpoint
dataset="`$ECHO $ZONEPATH | $SED 's/.\(.*\)/\1/'`"
# Set disk quota for installed zone
$ZFS set quota=$QUOTA $dataset
retcode=`$ECHO $?`
case "$retcode" in
0) $ECHO "*** Quota $QUOTA installation successful";;
*) $ECHO "*** Quota installation has errors";;
esac
}

##############
# Main block #
##############

# OS version checking
os_check

# Superuser check
root_check

# Check command-line arguments
if [ "x$*" = "x" ]; then
# If arguments list empty, show usage note
usage
else
arg_list=$*
# Parse command line
set -- `$GETOPT iInNsShH: $arg_list` || {
usage
}

# Read arguments
for i in $arg_list
do
case $i in
-i|-I) print_zone_info="1";;
-n|-N) non_interactive="1";;
-s|-S) skip_installation="1";;
-h|-H|\?) usage;;
*) shift
config_file=$1
break;;
esac
shift
done

# Remove trailing --
shift `$EXPR $OPTIND - 1`
fi

# Get zone config file
get_cfg_file $config_file

# Check zone exists
check_zone_name

# Check zone type and configure appropriate
if [ "$ZONE_TYPE" = "sparse" ]; then
sparse_root_zone
elif [ "$ZONE_TYPE" = "whole" ]; then
whole_root_zone
else
$ECHO "ERROR: Unknown zone type. Must be 'sparce' or 'whole' value. Exiting..."
exit 1
fi

$ECHO "Zone $ZONE configured."
$ECHO "______________________"
# Print configured zone info if requested
if [ "$print_zone_info" = "1" ]; then
$ZONECFG -z $ZONE info
$ECHO "______________________"
fi
# Skip installation if required
if [ "$skip_installation" = "1" ]; then
$ECHO "Installation not performed. Exiting..."
exit 0
fi
# Bypass interactive mode if required
if [ "$non_interactive" != "1" ]; then
$ECHO "Press to install zone or to cancel."
read p
fi

# Install zone
install_configured_zone

# Setting disk quota
set_disk_quota

exit 0

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

Структура конфигурационного файла (пример) приведена ниже.

Конфигурационный файл zone1.cfg
__________________________

#
# Define zone components
#

# Zone type. Sparse root or whole root.
# Default is sparse.
#ZONE_TYPE="whole"
ZONE_TYPE="sparse"

# Zone name
ZONE="zone1"
# Zone storage pool mountpoint.
# Zone dataset will be created during installation.
# Note: In order to create DATASET for zone (with quota)
# you MUST use top level storage pool at this parameter.
# Otherwise directory will be created for zone with
# global pool quota only!
ZONEDATA="/data"
# Zonepath forming from storage pool name and zonename
ZONEPATH="$ZONEDATA/$ZONE"

# CPU usage mode.
# If 0, shared CPU and FSS is using. If 1, then dedicated CPU is using.
DEDICATED_CPU="0"
# Default scheduling class
SCHEDCLASS="FSS"
# CPU shared
CPU="2"
# Capped CPU. Leave it blank if want to not set.
# Relative percent value. Specified only when DEDICATED_CPU is set to 0.
CAPPED_CPU=""
# CPU dedicated.
# Can be specified as range (i.e. 1-3) or single value (2).
NCPU="1-2"
# Relative resource pool importance
IMPORTANCE="2"

# Capped memory. Set to 1 to enable. Leave it blank for none.
# If set to 1, at least one of next three parameters must be specified.
CAPPED_MEM="1"
# Capped memory. If parameter is not specified, it will not be set.
MPHYS="256m"
MSWAP="256m"
MLOCK="256m"

# Filesystem
FS="/data/stage"
# Special value for fs
SPEC="/stage"
# Inherit pkg dir
IPD="/opt"
# Network address for zone
# Will be ignored if IP_TYPE specified to exclusive.
ADDR="192.168.192.10"
# Physical interface for zone
PHYS="e1000g0"
# Default router for zone. Leave it blank to none.
DEFROUTER=""
# IP type for zone. Specify "exclusive" value when appropriate.
# Leave it blank to default (shared).
IP_TYPE=""
# ZFS disk quota for zone
QUOTA="2G"

Выполнение скрипта
_______________

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

zoneinst.sh [-i] [-n] [-s] [-h] zoneX.cfg

где zoneX.cfg файл параметров зоны (обязательный).
-i - необязательная опция, включающая вывод всех параметров зоны после ее конфигурирования и до инсталляции.
-n - необязательная опция, включающая неинтерактивную инсталляцию зоны после ее конфигурирования и установку квоты на датасет зоны.
-s - необязательная опция, позволяющая пропустить инсталляцию и установку квоты датасета зоны (выполнить только конфигурирование зоны).
-h - необязательная опция, печатающая данную подсказку.

Вот, собственно говоря, и все. Теперь вы можете конфигурировать и устанавливать зоны легко и непринужденно, не вспоминая синтаксис zonecfg.

четверг, 2 декабря 2010 г.

ИНН и информационная безопасность: Separation of duties

Я уже писал, что, по моему мнению, введение ИНН проскочило мимо внимания экспертов по информбезопасности. И напрасно. Потому что то, что не заметили даже эксперты, тем более не заметят обычные рядовые смертные.

Дело, собственно, вот в чем.

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

Что мы имеем на самом деле?

На самом деле, после некоторого размышления, я пришел к выводу, что, скорее всего, мы имеем дело с нарушением одного из основополагающих принципов информационной безопасности, который специалистам известен как separation of duties или segregation of duties.

Говоря простым русским языком:

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

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

Второе. Лично мне физически неизвестны принципы построения ИС, хранящей персональные данные на основе ИНН.

Третье. Если система не имеет механизмов RBAC, то никакие законодательные меры не ограничат злоупотребление персональными данными. В данном случае я принципиально не согласен с гуманитариями от IT, которые заявляют, что "Человек-де не может являться самым слабым звеном ИС, поскольку он-де альфа и омега подообных систем, все для блага человека, все во имя человека". Да, да. Я даже знаю, как зовут этого человека.

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

Два простых слова. Цена вопроса.

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

Да, мне известна фраза "кто устережет самих сторожей".

Да, мне известно, что кому-то все равно придется иметь полный доступ к информации и этот "кто-то" будет не прекраснодушный и преисполненный этикой до самых глаз гуманитарий.

Да, мне известно, что конверт с тысячей баксов преодолеет угрызения совести большинства системных администраторов, а чуть более пухлый конверт - и совесть большинства служащих. Цена вопроса.

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

Сейчас просто вся информация будет доступна любому, имеющему доступ к системе, не только суперпользователю.

И еще - если раньше приходилось еще собирать (консолидировать) воедино большинство данных об одном человеке, к примеру, то сейчас даже этого делать не придется.

Все уже собрано, осталось только посмотреть ИНН на удостоверении - и привет, Большой Брат, мы видим и знаем то же самое, что и ты.

Повторяю, основополагающие принципы безопасности появились не вчера и не по желанию левой пятки IT-специалистов. Они проверены временем и практикой.

Почему эксперты по безопасности пропустили такой явный прокол в глобальном государственном проекте - мне тоже интересно было узнать. Видимо, потому, что никому это особо не интересно, так, происходит что-то на государственном уровне - да и черт с ним. А думать, в общем-то, уже и не обязательно. Зачем думать, для этого есть Лавочка. Там ведь не идиоты сидят. Наверное.

Есть мнение, что мышиная возня православных вокруг числа зверя в ИНН отвлекала внимание от подлинно серьезных аспектов реализации и силового введения подобных систем (а с другой стороны, куда ты нафиг денешься, если документы без ИНН просто тупо недействительны с определенной даты и со старыми документами нет ни тебя, ни твоего банковского счета).

Как бы то ни было, боржоми пить уже поздно. У вас, господа простые смертные, один год на обмен документов и получение ИНН. После этого вы не становитесь вне закона, конечно, но ваша жизнь осложнится до такой степени, что лучше вам уехать в скит в сибирской тайге.

среда, 1 декабря 2010 г.

Зоны Solaris IV: Ресурсные ограничения

Если создавать зоны так, как описано во всех популярных руководствах - т.е. описывать только абсолютный минимум параметров, например вот так:

root @ blade / # zonecfg -z zone1
zone1: No such zone configured
Use 'create' to begin configuring a new zone.
zonecfg:zone1
> create
zonecfg:zone1
> set autoboot=true
zonecfg:zone1
> set zonepath=/export/home2/zone1
zonecfg:zone1
> add net
zonecfg:zone1:net
> set address=192.168.100.10
zonecfg:zone1:net
> set physical=eri0
zonecfg:zone1:net
> end
zonecfg:zone1
> verify
zonecfg:zone1
> commit
zonecfg:zone1
> exit

root @ blade / # zoneadm list -vc
ID NAME STATUS PATH BRAND IP
0 global running / native shared
- zone1 configured /export/home2/zone1 native shared

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

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

Первая возможность - использовать ресурсные пулы, для чего активировать соответствующий сервис pools и воспользоваться командами pooladm, poolcfg и poolbind:

root @ blade / # svcs pools
STATE STIME FMRI
disabled 19:03:56 svc:/system/pools:default
root @ blade / # svcadm enable pools
root @ blade / # pooladm

system default
string system.comment
int system.version 1
boolean system.bind-default true
string system.poold.objectives wt-load

pool pool_default
int pool.sys_id 0
boolean pool.active true
boolean pool.default true
int pool.importance 1
string pool.comment
pset pset_default

pset pset_default
int pset.sys_id -1
boolean pset.default true
uint pset.min 1
uint pset.max 65536
string pset.units population
uint pset.load 5
uint pset.size 1
string pset.comment

cpu
int cpu.sys_id 0
string cpu.comment
string cpu.status on-line

root @ blade / # poolcfg
Usage:
poolcfg -h
poolcfg -c command [ -d | [ file ] ]
poolcfg -f command-file [-d | [ file ] ]

root @ blade / # poolbind
Usage: poolbind -p pool_name [-i pid | -i taskid | -i projid | -i zoneid] id ...
poolbind -q pid ...
poolbind -Q pid ...

Данный механизм весьма удобен, очень пригоден для больших и масштабируемых установок и серьеных продуктивных систем с большим количеством ресурсов, настолько большим, что использование ресурсных пулов становится оправданным.

Однако первоначальное планирование ресурсных пулов и их конфигурирование - задача не для начинающего администратора, и, в случае некрупных серверов, в общем, не слишком требуется.

Можно ли получить те же результаты несколько иным путем?

Можно.

По существу, для ограничения потребления ресурсов зоной и сохранения ее отзывчивости (а равно и отзывчивости глобальной зоны) требуется установка и контроль нескольких параметров:

- Класса планировщика задач
- Использования процессоров
- Использования памяти.

Самая основная установка - установка класса планировщика задач для неглобальной зоны. Устанавливается как глобальный параметр зоны:

zonecfg:zone1
> set scheduling-class=FSS

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

root @ blade / # dispadmin -l
CONFIGURED CLASSES
==================

SYS (System Class)
TS (Time Sharing)
SDC (System Duty-Cycle Class)

На практике выгодней использовать FSS (Fair Share Sheduler), так как обычно требуется достаточно высокая отзывчивость неглобальных зон, даже при серьезной перегрузке сервера.

Этого, однако, недостаточно для того, чтобы контролировать потребление зоной ресурсов основной системы.

Для контроля и принуждения зон к использованию процессоров и памяти можно использовать демон rcapd:

root @ blade / # svcs rcap
STATE STIME FMRI
disabled 19:03:56 svc:/system/rcap:default

который имеет интерфейс управления rcapadm:

root @ blade / # rcapadm -E
root @ blade / # svcs rcap
STATE STIME FMRI
online 20:16:26 svc:/system/rcap:default

и позволяет принуждать пользователей проектов (projects) к использованию ресурсных ограничений.

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

Ресурсы можно ограничивать глобальными установками зоны (man zonecfg):

Resources
The following resource types are supported:

capped-cpu

Limits for CPU usage.

capped-memory

Limits for physical, swap, and locked memory.

dataset

ZFS dataset.

dedicated-cpu

Subset of the system's processors dedicated to this zone
while it is running.

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

Это не единственные ресурсы, использование которых можно определить в зонах. Можно установить ограничения на процессы LWP и ресурсы IPC:

(global)

max-lwps

(global)

max-msg-ids

(global)

max-sem-ids

(global)

max-shm-ids

(global)

max-shm-memory

Вот как выглядит, например, задание выделенных процессоров для сконфигурированной (и остановленной) зоны:

zonecfg:zone1
> info
zonename: zone1
zonepath: /export/home2/zone1
brand: native
autoboot: true
bootargs:
pool:
limitpriv:
scheduling-class: FSS
ip-type: shared
hostid:
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
net:
address: 192.168.100.10
physical: eri0
defrouter not specified
zonecfg:zone1
> add dedicated-cpu
zonecfg:zone1:dedicated-cpu
> set ncpus=1
zonecfg:zone1:dedicated-cpu
> set importance=1
zonecfg:zone1:dedicated-cpu
> end
zonecfg:zone1
> info
zonename: zone1
zonepath: /export/home2/zone1
brand: native
autoboot: true
bootargs:
pool:
limitpriv:
scheduling-class: FSS
ip-type: shared
hostid:
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
net:
address: 192.168.100.10
physical: eri0
defrouter not specified
dedicated-cpu:
ncpus: 1
importance: 1

При необходимости можно удалить свойство dedicated-cpu, скажем, и перейти к модели cpu-shares:

zonecfg:zone1
> remove dedicated-cpu
zonecfg:zone1
> set cpu-shares=2
zonecfg:zone1
> add capped-cpu
zonecfg:zone1:capped-cpu
> set ncpus=2
zonecfg:zone1:capped-cpu
> end
zonecfg:zone1
> info
zonename: zone1
zonepath: /export/home2/zone1
brand: native
autoboot: true
bootargs:
pool:
limitpriv:
scheduling-class: FSS
ip-type: shared
hostid:
[cpu-shares: 2]
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
net:
address: 192.168.100.10
physical: eri0
defrouter not specified
capped-cpu:
[ncpus: 2.00]
rctl:
name: zone.cpu-shares
value: (priv=privileged,limit=2,action=none)
rctl:
name: zone.cpu-cap
value: (priv=privileged,limit=200,action=deny)

Обратите внимание, что использование cpu-shares и добавление capped-cpu приводит к автоматическому созданию ресурсных ограничителей rctl (так же, как и использование параметра capped-memory).

Параметр capped-cpu задает максимальную величину относительной загрузки разделяемых процессоров в процентах для каждого из совместно использованных процессоров.

Для отключения этих параметров и удаления ресурсных ограничителей зоны выполним следующие команды:

zonecfg:zone1
> clear cpu-shares
zonecfg:zone1
> info
zonename: zone1
zonepath: /export/home2/zone1
brand: native
autoboot: true
bootargs:
pool:
limitpriv:
scheduling-class: FSS
ip-type: shared
hostid:
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
net:
address: 192.168.100.10
physical: eri0
defrouter not specified
capped-cpu:
[ncpus: 2.00]
rctl:
name: zone.cpu-cap
value: (priv=privileged,limit=200,action=deny)
zonecfg:zone1
> remove rctl
zonecfg:zone1
> info
zonename: zone1
zonepath: /export/home2/zone1
brand: native
autoboot: true
bootargs:
pool:
limitpriv:
scheduling-class: FSS
ip-type: shared
hostid:
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
net:
address: 192.168.100.10
physical: eri0
defrouter not specified

Для ограничения использования памяти в зоне используется свойство capped-memory:

zonecfg:zone1
> add capped-memory
zonecfg:zone1:capped-memory
> set physical=256m
zonecfg:zone1:capped-memory
> set swap=256m
zonecfg:zone1:capped-memory
> set locked=128m
zonecfg:zone1:capped-memory
> end
zonecfg:zone1>

При добавлении capped-memory по минимуму достаточно указать только значение physical, swap и locked являются опциональными.

Еще одним важным ресурсом зоны является сетевой интерфейс. По умолчанию сетевой интерфейс используется в режиме shared, для каждой зоны создается логический интерфейс и назначается IP-адрес.

Для высоконагруженной зоны (в плане сетевого трафика) можно установить монопольное использование сетевого интерфейса одной зоной. В этом случае интерфейсу назначается IP-адрес в глобальной зоне (командой ifconfig) и при конфигурировании зоны указывается режим использования физического интерфейса exclusive:

zonecfg:zone1
> set ip-type=exclusive
zonecfg:zone1
> verify
net: address cannot be specified for an exclusive IP type
zone1: Invalid argument

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

zonecfg:zone1
> remove net
zonecfg:zone1
> add net
zonecfg:zone1:net
> set physical=eri0
zonecfg:zone1:net
> end
zonecfg:zone1
> verify

Теперь конфигурация нашей зоны такая, какой мы хотели ее сделать и ее можно установить или запустить:

zonecfg:zone1
> verify
zonecfg:zone1
> info
zonename: zone1
zonepath: /export/home2/zone1
brand: native
autoboot: true
bootargs:
pool:
limitpriv:
scheduling-class: FSS
ip-type: exclusive
hostid:
inherit-pkg-dir:
dir: /lib
inherit-pkg-dir:
dir: /platform
inherit-pkg-dir:
dir: /sbin
inherit-pkg-dir:
dir: /usr
net:
address not specified
physical: eri0
defrouter not specified
capped-memory:
physical: 256M
[swap: 256M]
[locked: 128M]
rctl:
name: zone.max-swap
value: (priv=privileged,limit=268435456,action=deny)
rctl:
name: zone.max-locked-memory
value: (priv=privileged,limit=134217728,action=deny)


Как видно из приведенных примеров, ресурсные ограничители rctl добавляются в конфигурацию зоны без использования ресурсных пулов. Очевидно, что можно добавлять ресурсные ограничители и непосредственно, командой zonecfg add rctl.