AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / server / Perguntas / 1172420
Accepted
starfry
starfry
Asked: 2025-02-07 22:27:51 +0800 CST2025-02-07 22:27:51 +0800 CST 2025-02-07 22:27:51 +0800 CST

Mesclagem Keytab idempotente do MIT Kerberos

  • 772

Estou tentando escrever um script idempotente para Linux (MIT kerberos) que aplica um keytab dado por /etc/krb5.keytabmesclagem com seu conteúdo existente. No MacOS (que, acredito, usa Heimdal) é fácil:

ktutil copy /tmp/ktnew /etc/krb5.keytab

Se a(s) chave(s) /tmp/ktnewjá estiverem lá /etc/krb5.keytab, ela não será alterada (isso pode ser confirmado com hashes anteriores e posteriores).

A versão do MIT ktutilparece funcionar apenas interativamente e não tem um equivalente para copy. Usar rktand wktanexa (e, portanto, duplica) em vez de mesclar e, portanto, não é idempotente.

É possível fazer isso de forma idempotente (e não interativa) usando as ferramentas do MIT comumente encontradas em sistemas Linux?

kerberos
  • 1 1 respostas
  • 52 Views

1 respostas

  • Voted
  1. Best Answer
    grawity
    2025-02-08T00:46:25+08:002025-02-08T00:46:25+08:00

    Até onde eu sei, não. O MIT Krb5 também vem com o k5srvutilscript que depende do subcomando kadminnão interativo do ktrempara remover chaves substituídas (aquelas com um kvno mais antigo que o mais recente), mas é só isso que ele tem.

    Eu sugeriria que mesclar keytabs não é a coisa certa a se fazer em primeiro lugar – em vez de colocar tudo no keytab da "máquina" (e, portanto, ter que conceder a todos os serviços acesso ao keytab), você deve ter no máximohost/* e nfs/*lá, enquanto todo o resto deve usar arquivos keytab distintos. (Serviços que não suportam especificar um keytab nativamente geralmente suportam KRB5_KTNAME=por meio do ambiente.)

    A implantação de keytabs se tornaria tão simples quanto substituir o arquivo inteiro.

    Em meus próprios projetos (especificamente em uma ferramenta que tenta solicitar idempotentemente uma chave via kadmin's ktadd), eu analiso o keytab via Python para determinar se ele já tem uma chave para o principal prestes a ser adicionado. Aqui está um ponto de partida:

    # binary_io.py (not the tidiest class, merely something I'd been carrying
    # around in various different projects over the years)
    import io
    import struct
    
    class StreamWrapper():
        def __init__(self, fh=b""):
            if isinstance(fh, bytes) or isinstance(fh, bytearray):
                self.fh = io.BytesIO(fh)
            elif hasattr(fh, "makefile"):
                self.fh = fh.makefile("rwb")
            else:
                self.fh = fh
    
        def seek(self, pos, whence=0):
            return self.fh.seek(pos, whence)
    
        def tell(self):
            return self.fh.tell()
    
        def read(self, length):
            buf = self.fh.read(length)
            if len(buf) < length:
                if len(buf) == 0:
                    raise EOFError("Hit EOF after %d/%d bytes" % (len(buf), length))
                else:
                    raise IOError("Hit EOF after %d/%d bytes" % (len(buf), length))
            return buf
    
        def write(self, buf):
            return self.fh.write(buf)
    
        def flush(self):
            return self.fh.flush()
    
    class BinaryReader(StreamWrapper):
        def _read_fmt(self, length, fmt):
            data, = struct.unpack(fmt, self.read(length))
            return data
    
        def read_u8(self):
            return self._read_fmt(1, "B")
    
        def read_u16_le(self):
            return self._read_fmt(2, "<H")
    
        def read_u16_be(self):
            return self._read_fmt(2, ">H")
    
        def read_u32_le(self):
            return self._read_fmt(4, "<L")
    
        def read_u32_be(self):
            return self._read_fmt(4, ">L")
    
        def read_u64_le(self):
            return self._read_fmt(8, "<Q")
    
        def read_u64_be(self):
            return self._read_fmt(8, ">Q")
    
    class BinaryWriter(StreamWrapper):
        def _write_fmt(self, fmt, *args):
            return self.write(struct.pack(fmt, *args))
    
        def write_u8(self, val):
            return self._write_fmt("B", val)
    
        def write_u16_le(self, val):
            return self._write_fmt("<H", val)
    
        def write_u16_be(self, val):
            return self._write_fmt(">H", val)
    
        def write_u32_le(self, val):
            return self._write_fmt("<L", val)
    
        def write_u32_be(self, val):
            return self._write_fmt(">L", val)
    
        def write_u64_le(self, val):
            return self._write_fmt("<Q", val)
    
        def write_u64_be(self, val):
            return self._write_fmt(">Q", val)
    
    class BinaryStream(BinaryReader, BinaryWriter):
        pass
    
    # -----
    # kerberos.py
    
    from dataclasses import dataclass
    
    # Format documentation:
    #   https://web.mit.edu/kerberos/krb5-latest/doc/formats/keytab_file_format.html
    #   https://www.gnu.org/software/shishi/manual/html_node/The-Keytab-Binary-File-Format.html
    
    # The default name type
    KRB5_NT_PRINCIPAL = 1
    
    @dataclass
    class Principal:
        nametype: int
        components: list[bytes]
        realm: bytes
    
        def unparse(self):
            # Mostly but not 100% correct
            sz = [s.replace(b"/", b"\\/") for s in self.components]
            sz = b"@".join([b"/".join(self.components), self.realm])
            return sz.decode()
    
    @dataclass
    class KeytabEntry:
        principal: Principal
        timestamp: int
        kvno: int
        enctype: int
        keydata: bytes
    
    class KrbBinaryReader(BinaryReader):
        # Turns out *nothing* is common between the two formats. Principals have
        # their name_type in a different place. Even 'data' has a 32-bit length in
        # ccache and 16-bit length in keytab.
    
        uses_native_endian = True
    
        def read_u16(self):
            if self.uses_native_endian:
                return self._read_fmt(2, "=H")
            else:
                return self.read_u16_be()
    
        def read_u32(self):
            if self.uses_native_endian:
                return self._read_fmt(4, "=L")
            else:
                return self.read_u32_be()
    
        def read_s32(self):
            if self.uses_native_endian:
                return self._read_fmt(4, "=l")
            else:
                return self._read_fmt(4, ">l")
    
        def read_time(self):
            return self.read_u32()
    
        def tell_eof(self):
            start_pos = self.tell()
            self.seek(0, 2)
            end_pos = self.tell()
            self.seek(start_pos)
            return end_pos
    
    class KeytabReader(KrbBinaryReader):
        version = None
    
        def read_data(self):
            length = self.read_u16()
            value = self.read(length)
            return value
    
        def read_principal(self):
            n_components = self.read_u16()
            if self.version == 1:
                n_components -= 1
            realm = self.read_data()
            components = []
            for i in range(n_components):
                components.append(self.read_data())
            name_type = KRB5_NT_PRINCIPAL
            if self.version >= 2:
                name_type = self.read_u32()
            return Principal(name_type, components, realm)
    
        def read_entry(self, size):
            end_pos = self.tell() + size
            principal = self.read_principal()
            timestamp = self.read_time()
            kvno = self.read_u8()
            enctype = self.read_u16()
            keydata = self.read_data()
            if end_pos - self.tell() >= 4:
                kvno = self.read_u32()
            # Skip to end of slot
            self.seek(end_pos)
            return KeytabEntry(principal, timestamp, kvno, enctype, keydata)
    
        def read_keytab(self):
            major = self.read_u8()
            if major != 5:
                raise IOError("Keytab major version not recognized")
            minor = self.read_u8()
            if not (1 <= minor <= 2):
                raise IOError("Keytab minor version not recognized")
            self.version = minor
            self.uses_native_endian = (self.version == 1)
            end_pos = self.tell_eof()
            while self.tell() < end_pos:
                length = self.read_s32()
                if length > 0:
                    yield self.read_entry(length)
                elif length < 0:
                    # Skip an empty slot
                    self.read(-length)
                else:
                    break
    
    # ---
    
    class Keytab():
        def __init__(self, path):
            self.path = path
    
        def list_principals(self):
            with open(self.path, "rb") as fh:
                rd = KeytabReader(fh)
                for e in rd.read_keytab():
                    principal = e.principal.unparse()
                    yield principal.rsplit("@", 1)[0]
    
        def has_principal(self, principal):
            if not os.path.exists(self.path):
                return False
            return principal in {*self.list_principals()}
    
    • 0

relate perguntas

  • A delegação baseada em recursos do Windows Admin Center parou de funcionar com o erro KRB_AP_ERR_MODIFIED

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Você pode passar usuário/passar para autenticação básica HTTP em parâmetros de URL?

    • 5 respostas
  • Marko Smith

    Ping uma porta específica

    • 18 respostas
  • Marko Smith

    Verifique se a porta está aberta ou fechada em um servidor Linux?

    • 7 respostas
  • Marko Smith

    Como automatizar o login SSH com senha?

    • 10 respostas
  • Marko Smith

    Como posso dizer ao Git para Windows onde encontrar minha chave RSA privada?

    • 30 respostas
  • Marko Smith

    Qual é o nome de usuário/senha de superusuário padrão para postgres após uma nova instalação?

    • 5 respostas
  • Marko Smith

    Qual porta o SFTP usa?

    • 6 respostas
  • Marko Smith

    Linha de comando para listar usuários em um grupo do Windows Active Directory?

    • 9 respostas
  • Marko Smith

    O que é um arquivo Pem e como ele difere de outros formatos de arquivo de chave gerada pelo OpenSSL?

    • 3 respostas
  • Marko Smith

    Como determinar se uma variável bash está vazia?

    • 15 respostas
  • Martin Hope
    Davie Ping uma porta específica 2009-10-09 01:57:50 +0800 CST
  • Martin Hope
    kernel O scp pode copiar diretórios recursivamente? 2011-04-29 20:24:45 +0800 CST
  • Martin Hope
    Robert ssh retorna "Proprietário incorreto ou permissões em ~/.ssh/config" 2011-03-30 10:15:48 +0800 CST
  • Martin Hope
    Eonil Como automatizar o login SSH com senha? 2011-03-02 03:07:12 +0800 CST
  • Martin Hope
    gunwin Como lidar com um servidor comprometido? 2011-01-03 13:31:27 +0800 CST
  • Martin Hope
    Tom Feiner Como posso classificar a saída du -h por tamanho 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich O que é um arquivo Pem e como ele difere de outros formatos de arquivo de chave gerada pelo OpenSSL? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent Como determinar se uma variável bash está vazia? 2009-05-13 09:54:48 +0800 CST

Hot tag

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve