Enhavolisto

Antaŭa temo

Konkurso pri kreo de vortaro de “Juna Amiko”

Sekva temo

Esperantigo de SNAP 4.0

Kiel uzi ĉifritan .netrc dosieron en pitonaj skriptoj

Resumo:priskribo kiel sekure konservi informojn pri kontoj (uzantonomoj, pasvortoj) kaj uzi ilin en pitonaj skriptoj.

Komencaj eksplikoj

En mia laboro, mi plurfoje devas konekti al diversaj Oracle datumbazoj, en kiuj mi havas diversajn uzantonomojn kaj pasvortojn. Ĉar la nombro de tiuj kontoj kreskis nun ĝis 23, memori ĉiujn kaj tajpi ilin ĉe ĉiu datumbaza aliro, fariĝis malracia.

Konservi ilin en teksta dosiero estas danĝera afero, tial mi bezonis ilin ĉifri.

Post iom da esplorado, mi decidis uzi .netrc dosieron por konservi ĉiujn informojn pri kontoj kaj uzi GnuPG por ĝin ĉifri. Ambaŭ estas apogataj de normaj moduloj de Pitono (tamen la modulon netrc.py mi devis iomete ŝanĝi).

Kiel ĝi funkcias

La tuta ideo estas relative simpla:

  1. Oni kreas .netrc dosieron (vidu pliajn detalojn sube).

  2. La kreitan dosieron oni ĉifras per GnuPG:

    gpg --armour -r <nomo de uzanto de ĉifrilo> --encrypt <netrc dosiero>
  3. Oni konservas nur la ĉifritan dosieron (kutime ĝi havas finaĵon asc),

    Averto

    Memoru detrui la neĉifritan fontan .netrc dosieron sekure - ne per simpla delrm (uzu ekz. srmshred).

  4. La ĉifrita dosiero estas deĉifrata nur en momento de rulo de la skripto kaj neniu deĉifrita informo aperas ie ajn (krom komputila memoro).

.netrc dosiero

Ĝi estas vaste (en *niksoj) uzata dosiero, kiu priskribas kontoj de ftp konektoj en plata teksta formo. Ĝi bonege taŭgas por tiu ĉi celo, ĉar ĝi estas facile (de)ĉifrebla kaj apogata de Pitona modulo netrc.

La formo de .netrc dosiero estas jena:

machine <kontonomo>
    login <uzantonomo>
    password  <pasvorto>
    account <krompasvorto>
    macdef <difino de makroo>

La partoj de la kontopriskribo povas esti disigataj aŭ per novlinioj (kiel tie ĉi) aŭ per aliaj spacosignoj (spacetoj, taboj). La partoj de la priskriboj ne estas ĉiuj devigaj, ekzemple mi uzas nur login kaj password kaj la machine estas nomo de datumbazo.

Averto

La machine parto devas esti kongrua kun tnsnames.ora por ke sistemo sciu pri kiu datumbazo temas.

Krome, povas ekzisti ankaŭ apriora konto, kiu estas liverata se oni ne trovas la ĝustan:

default
    login <uzantonomo>
    password  <pasvorto>
    account <krompasvorto>
    macdef <difino de makroo>

netrc.py skripto

La norma pitona modulo netrc ebligas nur legi la neĉifritan .netrc dosieron, kaj tie ĉi estas ja bezonata legado do la ĉifrita dosiero. Tial mi ŝanĝis la modulon por ke ĝi ankaŭ legu la krudan tekston - en __init__ ĝi havas novan parton:

try:
    fp = open(file)
# komenco de nova parto
except IOError:
    fp = StringIO.StringIO(file)
except TypeError:
    fp = StringIO.StringIO(file)
# fino de nova parto
except KeyError:
    raise IOError("Could not find " + file)

kiu provas malfermi dosieron (norme estas provizita dosiernomo) kaj se tio ne sukcesas (estiĝas eraro), ĝi kreas fluon (kvazaŭ-dosieron) el provizita teksto aŭ estigas eraron kun mesaĝo.

Noto

La kodostilo kun reago al estiĝantaj eraroj estas kongrua kun EAFP (pli facilas pardoni forgeson ol peti permeson).

La ŝanĝita modulo elŝuteblas de tie: netrc.py.

Malebligo de norma netrc

Memoru, ke oni devas malebligi uzon de norma modulo netrc ekz. ŝanĝante ĝian nomon al netrc_.py aŭ anstataŭi ĝin per la ŝanĝita.

Oni povas ankaŭ uzi alian nomon por la ŝanĝita modulo - ekz. netrc1.py. Tiam oni ĝin uzu en la skripto importante:

import netrc1

Uzo

La informoj ĉifritaj en dosiero .netrc.asc estas nun uzeblaj per skripto:

import cx_Oracle  # konekti al Oracle datumbazo
import netrc  # legi netrc dosieron
import gnupg  # malĉifri netrc dosieron
from locale import getpreferredencoding  # difni enkodigon uzatan de la sistemo

# agordoj de GnuPG
gpg = gnupg.GPG(gnupghome=r'~\.gnupg')  # hejmdosierujo por GnuPG
gpg.encoding = getpreferredencoding()  # laŭ enkodigo uzata en la sistemo

def get_account(database):
    '''
    Legi informojn pri uzantononomo kaj pasvorto por pasigita konto
    (ĉi tie - nomo de datumbazo).

    :param database: nomo de datumbazo (kongrua kun tnsnames.ora)
    :type database: ĉeno

    :returns: uzanotnonomon kaj pasvorton
    :rtype: opo kun du ĉenoj
    '''

    encrypted_file = open(r'~\.gnupg\.netrc.asc')
    decrypted_data = gpg.decrypt_file(encrypted_file)
    # malĉifri dosieron

    auth = netrc.netrc(unicode(decrypted_data))
    # pritrakti informojn de pasigita teksto (enhavo de malĉifrita dosiero)

    user, account, password = auth.authenticators(database)
    # legi informojn pri uzanotnonomo, kroma pasvorto kaj pasvorto de
    # pasigita konto

    return user, password

if __name__ == '__main__':
    database = 'BAZO1'  # ĝi kongruu kun 'machine' parto en via netrc dosiero
    user, password = get_account(database)

    connection = cx_Oracle.connect(user, password, database)
    # konekti al la Oracle datumbazo

Mi esperas ke komentoj en la skripto estas memeksplikantaj.

Aliaj datumbazoj

Se oni volus utiligi la samon por aliaj datumbazoj, ŝanĝas nur la konektomaniero, ekzemple por Teradata:

import pyodbc  # konekti al datumbazo (anstataŭ `import cx_Oracle`)

# la resto de supra kodo
# ...

if __name__ == '__main__':
    database = 'TERADATA'  # ĝi kongruu kun 'machine' parto en via netrc dosiero
    user, password = get_account(database)

    connection = pyodbc.connect("DRIVER={{Teradata}};DBCNAME=126.185.19.35;UID={0};PWD={1};CHARSET=UTF8;".format(user, password))
    # konekti al la Teradata datumbazo

Noto

Oni devas pasigi la ĝustan adreson (IP numeron) kaj enkodigon.