[ English | Indonesia | Deutsch | 日本語 ]

Menyesuaikan Object Storage (Swift) Middleware

OpenStack Object Storage, dikenal sebagai swift ketika membaca kode, didasarkan pada Python Paste framework. Pengantar terbaik untuk arsitekturnya aktif di Read The Docs. Karena penggunaan framework proyek swift ini, Anda dapat menambahkan fitur ke proyek dengan menempatkan beberapa kode khusus dalam pipa proyek tanpa harus mengubah kode core apa pun.

Bayangkan sebuah skenario di mana Anda memiliki akses publik ke salah satu kontainer Anda, tetapi yang Anda inginkan adalah membatasi akses ke satu set IP berdasarkan daftar putih. Dalam contoh ini, kami akan membuat sepotong middleware untuk swift yang memungkinkan akses ke sebuah kontainer dari hanya satu set alamat IP, seperti yang ditentukan oleh item metadata dari kontainer. Hanya alamat IP yang Anda daftar putih secara eksplisit menggunakan metadata kontainer yang akan dapat mengakses kontainer.

Peringatan

Contoh ini hanya untuk tujuan ilustrasi. Seharusnya tidak digunakan sebagai solusi daftar putih IP kontainer tanpa pengembangan lebih lanjut dan pengujian keamanan yang luas.

Ketika Anda bergabung dengan sesi layar yang stack.sh dimulai dengan screen -r stack, Anda melihat layar untuk setiap layanan yang berjalan, yang bisa beberapa atau beberapa, tergantung pada berapa banyak layanan yang Anda konfigurasi DevStack untuk berlari.

Tanda bintang * menunjukkan jendela layar yang Anda lihat. Contoh ini menunjukkan kita sedang melihat jendela key kunci (untuk keystone):

0$ shell  1$ key*  2$ horizon  3$ s-proxy  4$ s-object  5$ s-container  6$ s-account

Tujuan dari layar windows adalah sebagai berikut:

shell

Shell tempat Anda bisa menyelesaikan pekerjaan

key*

Layanan keystone

horizon

Aplikasi web dasbor horizon

s-{name}

Layanan swift

To create the middleware and plug it in through Paste configuration:

Semua kode untuk OpenStack hidup di /opt/stack. Buka direktori swift di layar shell dan edit modul middleware Anda.

  1. Ubah ke direktori tempat Object Storage diinstal:

    $ cd /opt/stack/swift
    
  2. Buat file kode sumber Python ip_whitelist.py:

    $ vim swift/common/middleware/ip_whitelist.py
    
  3. Salin kode seperti yang ditunjukkan di bawah ini ke ip_whitelist.py. Kode berikut adalah contoh middleware yang membatasi akses ke sebuah kontainer berdasarkan alamat IP seperti yang dijelaskan di awal bagian. Middleware meneruskan permintaan ke aplikasi lain. Contoh ini menggunakan pustaka "swob" swift untuk membungkus permintaan dan respons Web Server Gateway Interface (WSGI) menjadi objek untuk berinteraksi dengan swift. Setelah selesai, simpan dan tutup file.

    # vim: tabstop=4 shiftwidth=4 softtabstop=4
    # Copyright (c) 2014 OpenStack Foundation
    # All Rights Reserved.
    #
    #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    #    not use this file except in compliance with the License. You may obtain
    #    a copy of the License at
    #
    #         http://www.apache.org/licenses/LICENSE-2.0
    #
    #    Unless required by applicable law or agreed to in writing, software
    #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    #    License for the specific language governing permissions and limitations
    #    under the License.
    
    import socket
    
    from swift.common.utils import get_logger
    from swift.proxy.controllers.base import get_container_info
    from swift.common.swob import Request, Response
    
    class IPWhitelistMiddleware(object):
        """
        IP Whitelist Middleware
    
        Middleware that allows access to a container from only a set of IP
        addresses as determined by the container's metadata items that start
        with the prefix 'allow'. E.G. allow-dev=192.168.0.20
        """
    
        def __init__(self, app, conf, logger=None):
            self.app = app
    
            if logger:
                self.logger = logger
            else:
                self.logger = get_logger(conf, log_route='ip_whitelist')
    
            self.deny_message = conf.get('deny_message', "IP Denied")
            self.local_ip = socket.gethostbyname(socket.gethostname())
    
        def __call__(self, env, start_response):
            """
            WSGI entry point.
            Wraps env in swob.Request object and passes it down.
    
            :param env: WSGI environment dictionary
            :param start_response: WSGI callable
            """
            req = Request(env)
    
            try:
                version, account, container, obj = req.split_path(1, 4, True)
            except ValueError:
                return self.app(env, start_response)
    
            container_info = get_container_info(
                req.environ, self.app, swift_source='IPWhitelistMiddleware')
    
            remote_ip = env['REMOTE_ADDR']
            self.logger.debug("Remote IP: %(remote_ip)s",
                              {'remote_ip': remote_ip})
    
            meta = container_info['meta']
            allow = {k:v for k,v in meta.iteritems() if k.startswith('allow')}
            allow_ips = set(allow.values())
            allow_ips.add(self.local_ip)
            self.logger.debug("Allow IPs: %(allow_ips)s",
                              {'allow_ips': allow_ips})
    
            if remote_ip in allow_ips:
                return self.app(env, start_response)
            else:
                self.logger.debug(
                    "IP %(remote_ip)s denied access to Account=%(account)s "
                    "Container=%(container)s. Not in %(allow_ips)s", locals())
                return Response(
                    status=403,
                    body=self.deny_message,
                    request=req)(env, start_response)
    
    
    def filter_factory(global_conf, **local_conf):
        """
        paste.deploy app factory for creating WSGI proxy apps.
        """
        conf = global_conf.copy()
        conf.update(local_conf)
    
        def ip_whitelist(app):
            return IPWhitelistMiddleware(app, conf)
        return ip_whitelist
    

    Ada banyak informasi berguna dalam env dan conf yang dapat Anda gunakan untuk memutuskan apa yang harus dilakukan dengan permintaan tersebut. Untuk mengetahui lebih lanjut tentang properti apa yang tersedia, Anda dapat memasukkan pernyataan log berikut ke dalam metode __init__:

    self.logger.debug("conf = %(conf)s", locals())
    

    dan pernyataan log berikut ke dalam metode __call__:

    self.logger.debug("env = %(env)s", locals())
    
  4. Untuk menghubungkan middleware ini ke swift Paste pipeline, Anda mengedit satu file konfigurasi, /etc/swift/proxy-server.conf:

    $ vim /etc/swift/proxy-server.conf
    
  5. Temukan bagian [filter: ratelimit] `` di ``/etc/swift/proxy-server.conf, dan salin di bagian konfigurasi berikut setelahnya:

    [filter:ip_whitelist]
    paste.filter_factory = swift.common.middleware.ip_whitelist:filter_factory
    # You can override the default log routing for this filter here:
    # set log_name = ratelimit
    # set log_facility = LOG_LOCAL0
    # set log_level = INFO
    # set log_headers = False
    # set log_address = /dev/log
    deny_message = You shall not pass!
    
  6. Temukan bagian [pipeline: main] `` di ``/etc/swift/proxy-server.conf, dan tambahkan ip_whitelist setelah ratelimit ke daftar seperti itu. Setelah selesai, simpan dan tutup file:

    [pipeline:main]
    pipeline = catch_errors gatekeeper healthcheck proxy-logging cache bulk tempurl ratelimit ip_whitelist ...
    
  7. Mulai ulang layanan swift proxy untuk menjadikan swift menggunakan middleware Anda. Mulailah dengan beralih ke layar swift-proxy:

    1. Tekan Ctrl+A diikuti oleh 3.

    2. Tekan Ctrl+C untuk membunuh layanan.

    3. Tekan Up Arrow untuk memunculkan perintah terakhir.

    4. Tekan Enter untuk menjalankannya.

  8. Uji middleware Anda dengan CLI swift. Mulailah dengan beralih ke layar shell dan selesai dengan beralih kembali ke layar swift-proxy untuk memeriksa output log:

    1. Teken  Ctrl+A diikuti oleh 0.

    2. Pastikan Anda berada di direktori devstack:

      $ cd /root/devstack
      
    3. Sumber openrc untuk mengatur variabel lingkungan Anda untuk CLI:

      $ . openrc
      
    4. Buat kontainer yang disebut middleware-test:

      $ swift post middleware-test
      
    5. Tekan Ctrl+A diikuti oleh 3 untuk memeriksa output log.

  9. Di antara pernyataan log Anda akan melihat baris:

    proxy-server Remote IP: my.instance.ip.address (txn: ...)
    proxy-server Allow IPs: set(['my.instance.ip.address']) (txn: ...)
    

    Kedua pernyataan ini diproduksi oleh middleware kami dan menunjukkan bahwa permintaan dikirim dari instance DevStack kami dan diizinkan.

  10. Uji middleware dari luar DevStack pada mesin jarak jauh yang memiliki akses ke instance DevStack Anda:

    1. Instal klien keystone dan swift di mesin lokal Anda:

      # pip install python-keystoneclient python-swiftclient
      
    2. Cobalah untuk membuat daftar objek dalam kontainer middleware-test:

      $ swift --os-auth-url=http://my.instance.ip.address:5000/v2.0/ \
        --os-region-name=RegionOne --os-username=demo:demo \
        --os-password=devstack list middleware-test
      Container GET failed: http://my.instance.ip.address:8080/v1/AUTH_.../
          middleware-test?format=json 403 Forbidden   You shall not pass!
      
  11. Tekan Ctrl+A diikuti oleh 3 untuk memeriksa output log. Lihatlah pernyataan log swift lagi, dan di antara laporan log, Anda akan melihat baris:

    proxy-server Authorizing from an overriding middleware (i.e: tempurl) (txn: ...)
    proxy-server ... IPWhitelistMiddleware
    proxy-server Remote IP: my.local.ip.address (txn: ...)
    proxy-server Allow IPs: set(['my.instance.ip.address']) (txn: ...)
    proxy-server IP my.local.ip.address denied access to Account=AUTH_... \
       Container=None. Not in set(['my.instance.ip.address']) (txn: ...)
    

    Di sini kita dapat melihat bahwa permintaan ditolak karena alamat IP jarak jauh tidak dalam set IP yang diizinkan.

  12. Kembali ke instance DevStack Anda pada layar shell, tambahkan beberapa metadata ke kontainer Anda untuk memungkinkan permintaan dari mesin jarak jauh:

    1. Tekan Ctrl+A diikuti oleh 0.

    2. Tambahkan metadata ke kontainer untuk memungkinkan IP:

      $ swift post --meta allow-dev:my.local.ip.address middleware-test
      
    3. Sekarang coba perintah dari Langkah 10 lagi dan berhasil. Tidak ada benda di dalam kontainer, jadi tidak ada yang perlu didaftar; Namun, tidak ada kesalahan untuk dilaporkan.

      Peringatan

      Pengujian fungsional seperti ini bukan pengganti untuk pengujian unit dan integrasi yang tepat, tetapi berfungsi untuk membantu Anda memulai.

Anda bisa mengikuti pola serupa di proyek lain yang menggunakan framework Python Paste. Cukup buat modul middleware dan pasang melalui konfigurasi. Middleware berjalan secara berurutan sebagai bagian dari project's pipeline itu dan dapat memanggil layanan lain yang diperlukan. Tidak ada kode inti proyek yang disentuh. Cari nilai pipeline di file konfigurasi conf atau ini proyek di /etc/<project> untuk mengidentifikasi proyek yang menggunakan Paste.

Ketika middleware Anda selesai, kami menganjurkan Anda untuk membuka sumbernya dan memberi tahu komunitas di milis OpenStack. Mungkin orang lain membutuhkan fungsi yang sama. Mereka dapat menggunakan kode Anda, memberikan umpan balik, dan mungkin berkontribusi. Jika ada cukup dukungan untuk itu, mungkin Anda dapat mengusulkan agar itu ditambahkan ke swift resmi middleware<https://opendev.org/openstack/swift/src/branch/master/swift/common/middleware> _.