В данной статье мы решили поделиться одним из вариантов автоматизации процессов, необходимых для приема на работу или увольнения сотрудника. Особо полезна эта статья для PM, HR и непосредственно тех ребят, которые подготавливают рабочие места. Лично мое мнение — данную статью должен прочитать каждый, кто хочет минимизировать рутину в своей компании, ведь текучка персонала в той или иной степени есть везде.
Привет! Я Юра Ложкин, Atlassian Engineer в OS.ECO. Я занимался реализацией, тестированием и внедрением данного проекта в компании, и теперь делюсь этим опытом с вами.
Мы назвали этот проект «Сотрудники». У него есть всего один тип задачи — «Новый сотрудник». У этой задачи две основные функции:
При создании задачи на вывод сотрудника нужно указать:
На изображении выше идет проверка ФИО. В полях First Name и Last Name идет проверка того, указаны ли данные на латинице. А в поле ФИО — данные должны быть указаны на кириллице (и тут тоже идет проверка).
Выше изображена задача после ее создания.
Далее нам нужно создать пользователя в ERP, нажав на переход (ERP acc) в задаче. После успешной отработки скрипта, ERP возвращает Username — уникальное имя пользователя, которого больше нет в ERP, и employee_id — айди пользователя, используемый для блокировки учетной записи в будущем.
Вторым шагом создаем доступы для данного пользователя, нажав на переход (Enroll access) в задаче. Запускается джоба в Jenkins, которая и создает доступы на ресурсах компании, добавляет соответствующие права и создает почту (к примеру, на G Suite). На этом же этапе генерируется VPN-сертификат для пользователя и создается учетка в Duo. После этого пользователю на почту приходит письмо с доступами на корп. ресурсы.
Админу, который инициировал создание доступов, приходит сообщение в слак. Также в задаче будет добавлен скрытый комментарий с доступами:
Если же на данном этапе выполнения задачи что-то пошло не так, бот отправит сообщение в слак админу, который инициировал создание доступов:
User not created
See logs here
jenkins/job/generate_access/111
В целом, на этом работа хелпдеска заканчивается, и задача двигается дальше по воркфлоу.
Сотрудник в штате — статус Staff — и со всеми необходимыми доступами:
Поле Lastday необходимо для блокировки учетной записи в ERP. После перехода задачи в статус (Dismissal), который означает увольнение сотрудника, идет проверка учетки по всем ресурсам компании. Добавляется комментарий к задаче со списком ресурсов, которые проверялись.
Далее нажимаем на переход (Revoke Access). Запускается джоба, блокирующая все доступы сотрудника, которые были найдены. После успешной отработки в слак приходит сообщение со списком ресурсов, на которых была заблокирована учетная запись. И такое же сообщение добавляется в задаче в Jira в виде скрытого комментария.
Далее задача идет по воркфлоу, и в итоге попадает в статус Done — это говорит о том, что сотрудник уволен, доступы отозваны и техника принята.
Важно! Все комментарии к задаче добавляются скрытыми, их видит только сотрудник helpdesk.
На переходах генерации/проверки/отзыва доступов в Post Functions используется скрипт, написанный на SIL (Simple Issue Language), в котором передаются параметры в Jenkins и делается вызов API.
Ниже описан pipeline в Jenkins, в котором идет генерация доступов:
pipeline {
agent any
environment {
JIRA_USER = credentials('jira-user')
REFRESH_TOKEN = credentials('refresh_token')
duo_ik = credentials('duo_integration_key')
duo_sk = credentials('duo_secret_key')
duo_ah = credentials('duo_api_hostname')
}
options { timestamps() }
stages {
// создание учетной записи в IPA
stage('Create user account to LDAP') {
steps {
script {
if (env.ldap.toBoolean()) {
sh "bash ./create_access/ldaps/ipa.sh --uid ${uid} --first ${first} --last ${last} --domain ${domain} --pass ${env.pass}"
LDAP = "ipa01 password: ${env.pass}"
} else {
LDAP = "not used"
}
}
}
}
// создание почты
stage('Create mail account') {
steps {
script {
if (env.mail.toBoolean()) {
token = sh(script: 'curl -i -X POST https://www.googleapis.com/oauth2/v4/token -H "Content-Type: application/json" --data-binary "@${REFRESH_TOKEN}" | grep access_token | sed \'s/ \"access_token\": \"//\' | sed \'s/\",//\'', returnStdout: true).trim()
user = sh(returnStatus: true, script: """curl -H "Authorization: Bearer ${token}" -X POST -d \'{"primaryEmail": "${uid}@{domain}", "name": {"givenName": "${first}", "familyName": "${last}"}, "suspended": false, "password": "${env.pass}", "changePasswordAtNextLogin": true, "ipWhitelisted": false, "emails": [{"address": "${uid}@{domain}", "primary": true } ], "orgUnitPath": "/", "includeInGlobalAddressList": true }\' -H "Content-Type: application/json" -i https://www.googleapis.com/admin/directory/v1/users""")
MAIL = "Gsuite OS ECO"
} else {
MAIL = "not used"
}
}
}
}
// генерация сертификата впн
stage('Generate VPN certificate') {
steps {
script {
if (env.ldap.toBoolean() && env.mail.toBoolean() && env.vpn.toBoolean()) {
sh "ssh -o StrictHostKeyChecking=no -l jenkins vpn_server sudo python /opt/nice_vpn/manager/ldapcache.py"
sh "ssh -o StrictHostKeyChecking=no -l jenkins vpn_server sudo python /opt/nice_vpn/manager/cert-manager.py generate --login ${env.uid}"
show_cert = sh (returnStdout: true, script: "ssh -o StrictHostKeyChecking=no -l jenkins vpn_server sudo python /opt/nice_vpn/manager/cert-manager.py show-certs --login ${env.uid} | sed -n 4p | sed 's/|//g'")
vpn_ip = show_cert.split()[3]
vpn_cn = show_cert.split().last()
VPN = "vpn_server *ip*: ${vpn_ip} *CN*: ${vpn_cn}"
} else {
VPN = "not used"
}
}
}
}
// создание учетной записи в DUO
stage('Enroll duo mobile user') {
steps {
script {
if (env.ldap.toBoolean() && env.mail.toBoolean() && env.vpn.toBoolean()) {
fullname = first + ' ' + last
duo_user = sh(script: "python create_access/duo_create_user.py 'POST' ${env.duo_ah} '/admin/v1/users' 'username=${vpn_cn}&email=${env.uid}@${domain}&realname=${fullname}' ${env.duo_sk} ${env.duo_ik} 'XXXXXXXXXXXXXXXXXXX'", returnStdout: true).trim()
DUO = "OS ECO"
} else {
DUO = "not used"
}
}
}
}
// отправляет комментарий с доступами в задачу в джире
stage('Jira callback') {
steps {
script {
sh "curl -D- -H \"Authorization: Basic ${env.JIRA_USER}\" -X POST --data '{\"body\": \"Accesses created: \\n *LDAP* - ${LDAP} \\n *MAIL* - ${MAIL} \\n *VPN* - ${VPN} \\n *DUO* - ${DUO} \\n \", \"visibility\": {\"type\": \"role\",\"value\": \"Service Desk Team\"}}' -H \"Content-Type: application/json\" https://jira.os.eco/rest/api/2/issue/${issue}/comment"
}
}
}
}
post {
success {
script {
// отправляет сотруднику письмо с доступами
emailext body: '''${SCRIPT, template="notification.groovy"}''',
subject: 'Access ${project} | ${first} ${last}',
to: '${uid}@${domain}'
}
}
failure {
slackSend (
// в случае фейла, отправляет сообщение админу в слак
color: "danger",
channel: "@${env.admin}",
message: "*User not created* \n *See logs here* \n ${env.BUILD_URL}",
tokenCredentialId: "slack_bot"
)
}
}
}
Ранее на выдачу доступов тратилось около 20-30 минут, сейчас же — 2 минуты, что невероятно круто! Теперь сотрудники хелпдеск делают меньше рутинной работы, уменьшается риск человеческого фактора (где-то доступ не выдал, где-то разные логины и т.д.). При увольнении сотрудника идет проверка наличия его учетной записи на всех ресурсах компании, и если учетка есть, то она автоматически блокируется. Ситуация, когда «забыли забрать доступы», сводится к нулю.
Привет! Я Юра Ложкин, Atlassian Engineer в OS.ECO. Я занимался реализацией, тестированием и внедрением данного проекта в компании, и теперь делюсь этим опытом с вами.
Жизненный цикл задачи
В самом начале стоит сказать, что проект работает в связке Jira + Jenkins + Gitlab CI.Мы назвали этот проект «Сотрудники». У него есть всего один тип задачи — «Новый сотрудник». У этой задачи две основные функции:
- Создавать пользователя в ERP (база данных по учету ресурсов предприятия).
- Генерировать и блокировать доступы на корпоративные ресурсы.
Раскрываем все карты
«Заведение» сотрудника на ресурсы компанииПри создании задачи на вывод сотрудника нужно указать:
- Персональную информацию о новом сотруднике (ФИО, дату рождения, дату выхода).
- Доступы, которые необходимы для выполнения рабочих обязанностей.
- Домен компании, куда выходит сотрудник (для создания почты пользователя).
- Указываем должность, компанию, отдел и т.д.
- Указываем руководителя сотрудника и HR.
На изображении выше идет проверка ФИО. В полях First Name и Last Name идет проверка того, указаны ли данные на латинице. А в поле ФИО — данные должны быть указаны на кириллице (и тут тоже идет проверка).
Выше изображена задача после ее создания.
Далее нам нужно создать пользователя в ERP, нажав на переход (ERP acc) в задаче. После успешной отработки скрипта, ERP возвращает Username — уникальное имя пользователя, которого больше нет в ERP, и employee_id — айди пользователя, используемый для блокировки учетной записи в будущем.
Вторым шагом создаем доступы для данного пользователя, нажав на переход (Enroll access) в задаче. Запускается джоба в Jenkins, которая и создает доступы на ресурсах компании, добавляет соответствующие права и создает почту (к примеру, на G Suite). На этом же этапе генерируется VPN-сертификат для пользователя и создается учетка в Duo. После этого пользователю на почту приходит письмо с доступами на корп. ресурсы.
Админу, который инициировал создание доступов, приходит сообщение в слак. Также в задаче будет добавлен скрытый комментарий с доступами:
Если же на данном этапе выполнения задачи что-то пошло не так, бот отправит сообщение в слак админу, который инициировал создание доступов:
User not created
See logs here
jenkins/job/generate_access/111
В целом, на этом работа хелпдеска заканчивается, и задача двигается дальше по воркфлоу.
Сотрудник в штате — статус Staff — и со всеми необходимыми доступами:
Автоматическая генерация дополнительного VPN-сертификата на ПК или телефон
Когда сотрудник уже в штате, мы можем сгенерировать дополнительный VPN-сертификат прямо из задачи в Jira. В чем плюс данной генерации сертификата — сотруднику хелпдеск не обязательно иметь ssh доступ на сервер VPN. После нажатия на переход (Approval to generate VPN) сотрудник хелпдеска выбирает VPN-сервер и устройство, дальше задача переходит на руководителя. После согласования руководителем запускается джоба в Jenkins по генерации VPN. После успешной генерации сертификата бот добавит комментарий к задаче с данными VPN.Увольнение сотрудника
Когда сотрудник увольняется, открываем задачу по его выводу и нажимаем на переход (Dismissal), заполняем поле Lastday (последний рабочий день).Поле Lastday необходимо для блокировки учетной записи в ERP. После перехода задачи в статус (Dismissal), который означает увольнение сотрудника, идет проверка учетки по всем ресурсам компании. Добавляется комментарий к задаче со списком ресурсов, которые проверялись.
Далее нажимаем на переход (Revoke Access). Запускается джоба, блокирующая все доступы сотрудника, которые были найдены. После успешной отработки в слак приходит сообщение со списком ресурсов, на которых была заблокирована учетная запись. И такое же сообщение добавляется в задаче в Jira в виде скрытого комментария.
Далее задача идет по воркфлоу, и в итоге попадает в статус Done — это говорит о том, что сотрудник уволен, доступы отозваны и техника принята.
Важно! Все комментарии к задаче добавляются скрытыми, их видит только сотрудник helpdesk.
Техническая реализация проекта
На переходах создания и блокирования учетной записи в ERP в Post Functions используется скрипт, написанный на SIL (Simple Issue Language), в котором передаются параметры в ERP и делается вызов API.На переходах генерации/проверки/отзыва доступов в Post Functions используется скрипт, написанный на SIL (Simple Issue Language), в котором передаются параметры в Jenkins и делается вызов API.
Ниже описан pipeline в Jenkins, в котором идет генерация доступов:
pipeline {
agent any
environment {
JIRA_USER = credentials('jira-user')
REFRESH_TOKEN = credentials('refresh_token')
duo_ik = credentials('duo_integration_key')
duo_sk = credentials('duo_secret_key')
duo_ah = credentials('duo_api_hostname')
}
options { timestamps() }
stages {
// создание учетной записи в IPA
stage('Create user account to LDAP') {
steps {
script {
if (env.ldap.toBoolean()) {
sh "bash ./create_access/ldaps/ipa.sh --uid ${uid} --first ${first} --last ${last} --domain ${domain} --pass ${env.pass}"
LDAP = "ipa01 password: ${env.pass}"
} else {
LDAP = "not used"
}
}
}
}
// создание почты
stage('Create mail account') {
steps {
script {
if (env.mail.toBoolean()) {
token = sh(script: 'curl -i -X POST https://www.googleapis.com/oauth2/v4/token -H "Content-Type: application/json" --data-binary "@${REFRESH_TOKEN}" | grep access_token | sed \'s/ \"access_token\": \"//\' | sed \'s/\",//\'', returnStdout: true).trim()
user = sh(returnStatus: true, script: """curl -H "Authorization: Bearer ${token}" -X POST -d \'{"primaryEmail": "${uid}@{domain}", "name": {"givenName": "${first}", "familyName": "${last}"}, "suspended": false, "password": "${env.pass}", "changePasswordAtNextLogin": true, "ipWhitelisted": false, "emails": [{"address": "${uid}@{domain}", "primary": true } ], "orgUnitPath": "/", "includeInGlobalAddressList": true }\' -H "Content-Type: application/json" -i https://www.googleapis.com/admin/directory/v1/users""")
MAIL = "Gsuite OS ECO"
} else {
MAIL = "not used"
}
}
}
}
// генерация сертификата впн
stage('Generate VPN certificate') {
steps {
script {
if (env.ldap.toBoolean() && env.mail.toBoolean() && env.vpn.toBoolean()) {
sh "ssh -o StrictHostKeyChecking=no -l jenkins vpn_server sudo python /opt/nice_vpn/manager/ldapcache.py"
sh "ssh -o StrictHostKeyChecking=no -l jenkins vpn_server sudo python /opt/nice_vpn/manager/cert-manager.py generate --login ${env.uid}"
show_cert = sh (returnStdout: true, script: "ssh -o StrictHostKeyChecking=no -l jenkins vpn_server sudo python /opt/nice_vpn/manager/cert-manager.py show-certs --login ${env.uid} | sed -n 4p | sed 's/|//g'")
vpn_ip = show_cert.split()[3]
vpn_cn = show_cert.split().last()
VPN = "vpn_server *ip*: ${vpn_ip} *CN*: ${vpn_cn}"
} else {
VPN = "not used"
}
}
}
}
// создание учетной записи в DUO
stage('Enroll duo mobile user') {
steps {
script {
if (env.ldap.toBoolean() && env.mail.toBoolean() && env.vpn.toBoolean()) {
fullname = first + ' ' + last
duo_user = sh(script: "python create_access/duo_create_user.py 'POST' ${env.duo_ah} '/admin/v1/users' 'username=${vpn_cn}&email=${env.uid}@${domain}&realname=${fullname}' ${env.duo_sk} ${env.duo_ik} 'XXXXXXXXXXXXXXXXXXX'", returnStdout: true).trim()
DUO = "OS ECO"
} else {
DUO = "not used"
}
}
}
}
// отправляет комментарий с доступами в задачу в джире
stage('Jira callback') {
steps {
script {
sh "curl -D- -H \"Authorization: Basic ${env.JIRA_USER}\" -X POST --data '{\"body\": \"Accesses created: \\n *LDAP* - ${LDAP} \\n *MAIL* - ${MAIL} \\n *VPN* - ${VPN} \\n *DUO* - ${DUO} \\n \", \"visibility\": {\"type\": \"role\",\"value\": \"Service Desk Team\"}}' -H \"Content-Type: application/json\" https://jira.os.eco/rest/api/2/issue/${issue}/comment"
}
}
}
}
post {
success {
script {
// отправляет сотруднику письмо с доступами
emailext body: '''${SCRIPT, template="notification.groovy"}''',
subject: 'Access ${project} | ${first} ${last}',
to: '${uid}@${domain}'
}
}
failure {
slackSend (
// в случае фейла, отправляет сообщение админу в слак
color: "danger",
channel: "@${env.admin}",
message: "*User not created* \n *See logs here* \n ${env.BUILD_URL}",
tokenCredentialId: "slack_bot"
)
}
}
}
Вместо выводов
Сколько же времени теперь занимает вывод/увольнение сотрудника?Ранее на выдачу доступов тратилось около 20-30 минут, сейчас же — 2 минуты, что невероятно круто! Теперь сотрудники хелпдеск делают меньше рутинной работы, уменьшается риск человеческого фактора (где-то доступ не выдал, где-то разные логины и т.д.). При увольнении сотрудника идет проверка наличия его учетной записи на всех ресурсах компании, и если учетка есть, то она автоматически блокируется. Ситуация, когда «забыли забрать доступы», сводится к нулю.
Как настроить Jira для помощи отделу helpdesk при выходе или увольнении сотрудника
У цій статті йдеться про один із варіантів автоматизації процесів, необхідних для прийому на роботу або звільнення працівника. Особливо корисна ця стаття для PM, HR та безпосередньо тих, хто готує робочі місця. На думку автора, кожен, хто хоче мініміз
dou.ua