Ansible + Azure: дать пользователю разрешение на чтение файлов, принадлежащих root, которые не существуют на момент создания образа - PullRequest
0 голосов
/ 06 января 2019

Я использую Packer + Ansible для создания агента Linux TeamCity с использованием управляемого образа Windows Azure. Вот проблема, с которой я сталкиваюсь, описанная в серии шагов:

  1. Мой сценарий Ansible создает пользователя teamcity, которому необходимо будет прочитать файл из каталога /var/lib/waagent, когда код агента TeamCity будет помещен на виртуальную машину агента самим сервером сборки через Агент Push . Я назначаю 0755 разрешения для каталога /var/lib/waagent для teamcity внутри моего скрипта Ansible.

  2. Когда я создаю свой образ Linux через Packer + Ansible, на последнем этапе используется процесс waagent, отвечающий за управление лазурью, для удаления машины из эксплуатации. Методом проб и ошибок я обнаружил, что этот процесс удаляет каталог /var/lib/waagent как часть процедуры очистки.

  3. Когда TeamCity / Azure Portal / etc использует этот управляемый образ, который мы создали на первых двух шагах для создания новой виртуальной машины, создается новая папка /var/lib/waagent, но она принадлежит пользователю root .

  4. Когда код агента TeamCity выполняется под учетной записью teamcity, он выполняет следующую команду (изнутри своей среды выполнения Kotlin): /bin/sh -c "sudo cat /var/lib/waagent/ovf-env.xml" Сбой с ошибкой permission denied, и, следовательно, агент TeamCity невозможно использовать данные в файле ovf-env.xml для автоматической авторизации на сервере сборки - эту проблему я сейчас пытаюсь исправить.

У других пользователей были похожие проблемы с плагином TeamCity Azure, и им удалось исправить их, отредактировав файл /etc/sudoers: https://github.com/JetBrains/teamcity-azure-agent/issues/86#issuecomment-365042798

Я немного не в себе, когда дело доходит до системного администрирования Ansible и Linux, но вот что я попытался сделать в своем скрипте Ansible, чтобы помочь воспроизвести это решение в моей собственной среде:

- name: "Define dir list from dict"
  set_fact:
    dotnetcore_dirs: "\
      {{ dotnetcore_dirs | default([]) }} + \
      [ '/opt/{{ item.key }}' ]"
  with_dict: "{{ dotnetcore }}"

- set_fact:
    dotnetcore_dirs: "{{ dotnetcore_dirs }} + [ '{{ teamcity_agent_install_dir }}', '/var/lib/waagent' ]"

- name: Add TeamCity group
  group: "name={{ teamcity_agent_group }}"
  state: present
  become: true

- name: Add TeamCity user
  user:
    name: "{{ teamcity_agent_user }}"
    password: "{{ teamcity_agent_password | password_hash('sha512') }}"

- name: "Create Agent Build dirs"
  file:
    path: "{{ item }}"
    state: directory
    owner: "{{ teamcity_agent_user }}"
    group: "{{ teamcity_agent_group }}"
    mode: 0755
  with_items: "{{ dotnetcore_dirs }}"


- name: Modify sudoers file so we can cat /var/lib/waagent files
  blockinfile: 
    path: /etc/sudoers
    block: |
      %{{ teamcity_agent_group }} ALL=(ALL) NOPASSWD: ALL
    validate: 'visudo -cf %s'

- name: Add teamcity user to groups
  user:
    name: "{{ teamcity_agent_user }}"
    groups: "docker, {{ teamcity_agent_group }}"
    append: yes

До сих пор я не был успешным с таким подходом. Я могу выполнить следующую команду при подключении SSH к агенту TeamCity непосредственно из bash:

sudo cat /var/lib/waagent/ovf-env.xml

И с этим изображением можно просто прочитать содержимое файла.

Почему команда /bin/sh -c sudo cat /var/lib/waagent/ovf-env.xml терпит неудачу, когда она запускается здесь с помощью кода Kotlin агента TeamCity Azure? https://github.com/JetBrains/teamcity-azure-agent/blob/9d267ce798f8218fc153d5d73bc954ede52e1250/plugin-azure-agent/src/main/kotlin/jetbrains/buildServer/clouds/azure/FileUtilsImpl.kt#L43-L53

private fun readFileWithSudo(file: File): String {
        val commandLine = GeneralCommandLine()
        commandLine.exePath = UNIX_SHELL_PATH
        commandLine.addParameter("-c")
        commandLine.addParameter("sudo cat $file")

        val execResult = SimpleCommandLineProcessRunner.runCommand(commandLine, ByteArray(0))
        if (execResult.exitCode != 0) {
            throw IOException("Failed to read file: ${execResult.stderr}")
        }

        return execResult.stdout.trim()
    }

Этот код выполняется под учетной записью teamcity - так почему процесс, порожденный здесь Kotlin, не может сделать то, что может делать учетная запись teamcity с обычного терминала bash? Что я могу сделать, чтобы это исправить?

Редактировать: используется strace для отслеживания процесса запуска агента TeamCity, и вот соответствующие строки:

13565 stat("/var/lib/waagent", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13565 stat("/var/lib/waagent", {st_mode=S_IFDIR|0700, st_size=4096, ...}) = 0
13565 access("/var/lib/waagent", X_OK)  = 0
13565 open("/var/lib/waagent/ovf-env.xml", O_RDONLY) = -1 EACCES (Permission denied)
...