亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

keystone源碼分析(一)——Paste Deploy的應用

系統(tǒng) 1816 0

  本keystone源碼分析系列基于Juno版Keystone,于2014年10月16日隨Juno版OpenStack發(fā)布。

  Keystone作為OpenStack中的身份管理與授權模塊,主要實現(xiàn)系統(tǒng)用戶的身份認證、基于角色的授權管理、其他OpenStack服務的地址發(fā)現(xiàn)和安全策略管理等功能。Keystone作為開源云系統(tǒng)OpenStack中至關重要的組成部分,與OpenStack中幾乎所有的其他服務(如Nova, Glance, Neutron等)都有著密切的聯(lián)系。同時,Keystone作為開源的身份管理和授權系統(tǒng),對于其當前實現(xiàn)機制的探討已經(jīng)成為許多信息安全領域研究人員的一個重要方向,基于其提出的安全模型與擴展實現(xiàn)已經(jīng)很多,這里我們并不贅述這些學術成果。

  由于作者精力和能力有限,希望得到讀者的反饋與指正,轉載請注明出處。

  在分析任何一個系統(tǒng)前安裝并了解該系統(tǒng)的使用方法都是有益的,Keystone也不例外。關于如何安裝和配置Keystone請參考本博客的其他隨筆,這里我們假設讀者已經(jīng)熟悉OpenStack中每個服務的.conf和paste.ini配置文件的大體作用。

  首先介紹我的系統(tǒng)環(huán)境,由于重點關注Keystone的相關機理,我在團隊已有10臺服務器組成的小型云外搭建了一個Keystone的開發(fā)調試環(huán)境。當前使用的是Ubuntu 14.04 LTS Desktop,系統(tǒng)中的Keystone采用Ubuntu的apt工具安裝,源碼采用git下載,并且都是使用的Juno版本的分支,配置文件集中于/etc/keystone目錄下。

  首先我們查看/etc/keystone/keystone-paste.ini文件,這里簡要的介紹這個文件的大體結構與含義。

      
        #
      
      
         /etc/keystone/keystone-paste.ini
      
      
        

#
      
      
         filters
      
      
        [
        
          filter
        
        :token_auth]

paste.filter_factory 
      
      =
      
         keystone.middleware:TokenAuthMiddleware.factory


        
[ filter :admin_token_auth] paste.filter_factory
= keystone.middleware:AdminTokenAuthMiddleware.factory ... # applications [ app :service_v3] paste.app_factory = keystone.service:v3_app_factory ...
# pipelines [ pipeline :api_v3] pipeline = sizelimit url_normalize build_auth_context token_auth admin_token_auth xml_body_v3 json_body ec2_extension_v3 s3_extension simple_cert_extension revoke_extension service_v3 ...
# composites [ composite :main] use = egg:Paste # urlmap /v2.0 = public_api /v3 = api_v3 / = public_version_api [ composite :admin] use = egg:Paste # urlmap /v2.0 = admin_api /v3 = api_v3 / = admin_version_api

  可以發(fā)現(xiàn)這個文件事實上由若干filter, pipeline, application和composite的定義組成,在定義時并非必須嚴格按照這樣的順序進行隔離,這里為了分析的方便我們將其總結為這些段落。對于這些內容的具體含義,可以參考Paste Deploy和Python WSGI相關的介紹。

?  Keystone的代碼生態(tài)圈包括keystone, python-keystoneclient和keystonemiddleware。其中keystone以WSGI服務器的方式實現(xiàn),其監(jiān)聽python-keystoneclient和keystonemiddleware發(fā)送來的HTTP請求并作出相應響應。

  keystone-paste.ini文件事實上是一個paste-deploy配置文件,該文件由application, filter, pipeline, composite等定義段落組成。composite是第一層調度者,它粗略地根據(jù)不同的url類型將請求分配到不同的pipeline上。每一個pipeline由若干filter和一個application組成。正如其名,filter按照其在pipeline中的先后順序依次對http請求進行過濾,包括對參數(shù)進行格式化處理等操作。application位于pipeline的末尾,每一個pipeline只有一個application。最終通過所有filter的請求被application進一步調度到系統(tǒng)實現(xiàn)上每一個模塊的路由層(routers),路由層根據(jù)HTTP請求方法和具體的請求路徑,將HTTP請求分發(fā)給對應的控制層(controllers),controllers集中實現(xiàn)業(yè)務邏輯,并通過調用更低的驅動層完成底層的工作,如數(shù)據(jù)庫的讀寫等等。這些構成了composite, pipeline, filter, application和keystone實現(xiàn)間的邏輯關系。

  keystone-paste.ini文件從一個高層次定義了keystone所需的composite會將哪些類型的url交由由哪些pipeline, 每一個pipeline由哪些filter和app組成,以及具體到每一個filter和app是由系統(tǒng)源碼的哪一個部分實現(xiàn)的,事實上,從下文的分析可以看出,每一個filter在實現(xiàn)上都對應著一個特定的類,而每一個application在實現(xiàn)上則對應著一個具體的方法。

  以前文節(jié)選的部分keystone-paste.ini文件為例,我們以一個OpenStack系統(tǒng)要求的REST風格的HTTP請求視角看一下系統(tǒng)是如何實現(xiàn)的:

  當用戶以HTTP POST方式請求http://localhost:5000/v3/auth/tokens這個url時,意味著用戶希望進行身份認證,同時獲得keystone簽發(fā)的Token。當然,用戶需要在自己的HTTP請求中給出一些自己的身份信息,這樣keystone才能據(jù)以判斷該用戶是否是系統(tǒng)合法的用戶,并根據(jù)其擁有的角色和權限為其簽發(fā)token。

  下面是一個這樣的HTTP請求例子,采用cURL命令行工具模擬,-d 代表了POST方法,-i參數(shù)說明我們要求系統(tǒng)顯示未來獲得的響應(response)的header,-H參數(shù)指明了我們的請求攜帶的header,這里向keystone指出我們接受的網(wǎng)絡數(shù)據(jù)傳輸類型。

      curl -
      
        i \


      
      -H 
      
        "
      
      
        Content-Type: application/json
      
      
        "
      
      
         \


      
      -d 
      
        '


      
      
        {

    
      
      
        "
      
      
        auth
      
      
        "
      
      
        : {

        
      
      
        "
      
      
        identity
      
      
        "
      
      
        : {

            
      
      
        "
      
      
        methods
      
      
        "
      
      
        : [

                
      
      
        "
      
      
        password
      
      
        "
      
      
        

            ],

            
      
      
        "
      
      
        password
      
      
        "
      
      
        : {

                
      
      
        "
      
      
        user
      
      
        "
      
      
        : {

                    
      
      
        "
      
      
        domain
      
      
        "
      
      
        :{

                        
      
      
        "
      
      
        name
      
      
        "
      
      : 
      
        "
      
      
        Default
      
      
        "
      
      
        

                     },

                    
      
      
        "
      
      
        name
      
      
        "
      
      : 
      
        "
      
      
        USER_NAME
      
      
        "
      
      
        ,

                    
      
      
        "
      
      
        password
      
      
        "
      
      : 
      
        "
      
      
        PASSWORD
      
      
        "
      
      
        

                }

            }

         },

         
      
      
        "
      
      
        scope
      
      
        "
      
      
        : {

            
      
      
        "
      
      
        project
      
      
        "
      
      
        : {

                
      
      
        "
      
      
        domain
      
      
        "
      
      
        : {

                        
      
      
        "
      
      
        name
      
      
        "
      
      :
      
        "
      
      
        Default
      
      
        "
      
      
        

                },

               
      
      
        "
      
      
        name
      
      
        "
      
      : 
      
        "
      
      
        PROJECT
      
      
        "
      
      
        

            }

         }

     }

}
      
      
        '
      
      
         \
      
      

http:
      
        //127
      
      
        .0.0.1:5000/v3/auth/tokens
      
    

  系統(tǒng)首先根據(jù)paste-deploy配置文件結合請求的url類型(/v3)來判斷處理該請求的pipeline即api_v3,接著系統(tǒng)將該請求交由該pipeline來處理。pipeline api_v3中的所有filter會依次對該請求的header以及data等內容進行處理,比如過濾器sizelimit在進行一定的操作后,將其傳給下一個過濾器url_normalize,依次類推,直到給請求被傳遞給管道盡頭的application。

  我們以兩個filter為例進行探討,分別是token_auth和admin_token_auth,在該paste-deploy文件的filter定義字段,我們能夠找到這兩個filter的實現(xiàn)位置,事實上這也是系統(tǒng)搜尋每一個過濾器具體實現(xiàn)的依據(jù)??梢钥吹絫oken_auth是由keystone.middleware:TokenAuthMiddleware.factory實現(xiàn)的,那么我們到keystone/middleware/core.py中找到TokenAuthMiddleware這個類:

      
        #keystone/middleware/core.py
        

class
TokenAuthMiddleware(wsgi.Middleware): def process_request(self, request): token = request.headers.get(AUTH_TOKEN_HEADER) context = request.environ.get(CONTEXT_ENV, {}) context[ ' token_id ' ] = token if SUBJECT_TOKEN_HEADER in request.headers: context[ ' subject_token_id ' ] = ( request.headers.get(SUBJECT_TOKEN_HEADER)) request.environ[CONTEXT_ENV] = context

  發(fā)現(xiàn)該類繼承了wsgi.Middleware,說明這個類實質上是一個WSGI中間件。該中間件提取了http請求中的X-Auth-Token字段和(可選的)X-Subject-Token字段的值,將context中相應的字段填充為這兩個值,然后將修改后的上下文寫回到請求攜帶的環(huán)境信息中,傳遞給下一個filter即中間件admin_token_auth。再來看filter admin_token_auth是如何實現(xiàn)的,首先定位其實現(xiàn)的位置:keystone.middleware:AdminTokenAuthMiddleware.factory,接著到源碼keystone/middleware/core.py模塊下找到相應的AdminTokenAuthMiddleware類,

      
        #keystone/middleware/core.py
        

class
AdminTokenAuthMiddleware(wsgi.Middleware): """ A trivial filter that checks for a pre-defined admin token. Sets 'is_admin' to true in the context, expected to be checked by methods that are admin-only. """ def process_request(self, request): token = request.headers.get(AUTH_TOKEN_HEADER) context = request.environ.get(CONTEXT_ENV, {}) context[ ' is_admin ' ] = (token == CONF.admin_token) request.environ[CONTEXT_ENV] = context、

  可見這個過濾器的功能也非常簡單,就是從http請求header中的X-Auth-Token字段提取附帶的token,同時解析keystone主配置文件(keystone.conf)中[DEFAULT]字段下的admin_token選項,二者進行比對,如果結果相同,說明這個請求的發(fā)送者是我們系統(tǒng)默認的admin,在context字典的is_admin字段設1后寫回到請求的環(huán)境信息,否則在context字典的is_admin字段置0。當然,熟悉keystone官方文檔的用戶會發(fā)現(xiàn),在keystone的官方文檔中強烈建議生產(chǎn)環(huán)境中刪除該中間件,同時不設置keystone.conf文件中[DEFAULT]字段下的admin_token選項,因為該token的出示者將會獲得系統(tǒng)的最高權限,因此禁用該賬戶能夠避免一些不必要的攻擊。

  從上面的兩個例子可以看到,每一個filter進行一個具體的操作,這些操作比較簡單和獨立,彼此按先后順序串聯(lián)起來,如本例中的過濾器token_auth放置在過濾器admin_token_auth之前,這就使得系統(tǒng)在對context的is_admin字段進行填充以前,會對token_id和subject_token_id字段進行填充。

  最后我們看一下application是如何實現(xiàn)的。在pipeline api_v3的末端對應著最終的服務器應用service_v3,我們根據(jù)keystone-paste.ini文件中給出的位置paste.app_factory = keystone.service:v3_app_factory找到該app的具體實現(xiàn):keystone/service.py,

      
        #
      
      
        keystone/service.py
      
      

...
      
@fail_gracefully def v3_app_factory(global_conf, ** local_conf): controllers.register_version( ' v3 ' ) mapper = routes.Mapper() sub_routers = [] _routers = [] router_modules = [assignment, auth, catalog, credential, identity, policy] if CONF.trust.enabled: router_modules.append(trust) for module in router_modules: routers_instance = module.routers.Routers() _routers.append(routers_instance) routers_instance.append_v3_routers(mapper, sub_routers) # Add in the v3 version api sub_routers.append(routers.VersionV3( ' admin ' , _routers)) sub_routers.append(routers.VersionV3( ' public ' , _routers)) return wsgi.ComposingRouter(mapper, sub_routers)
...

  可以看到,該application將會實現(xiàn)第二層路由(第一層由keystone-paste.ini文件中的composite字段實現(xiàn)),此次路由將具體的請求處理工作進一步分發(fā)到系統(tǒng)的各個模塊上,比如代碼中的assignment,auth, catalog等等。由具體的模塊根據(jù)請求的具體路徑和內容完成具體功能。

  裝飾器@fail_gracefully在keystone/service.py中也有定義,主要功能是包裹住前文中的函數(shù)v3_app_factory,正如名稱所示,讓被裝飾的v3_app_factory()函數(shù)能夠“優(yōu)雅”地執(zhí)行,而由fail_gracefully()來處理可能的日志記錄和異常處理等善后工作。

      
        #
      
      
        keystone/service.py
      
      
        

...


      
      
        def
      
      
         fail_gracefully(f):

    
      
      
        """
      
      
        Logs exceptions and aborts.
      
      
        """
      
      
        

    @functools.wraps(f)

    
      
      
        def
      
       wrapper(*args, **
      
        kw):

        
      
      
        try
      
      
        :

            
      
      
        return
      
       f(*args, **
      
        kw)

        
      
      
        except
      
      
         Exception as e:

            LOG.debug(e, exc_info
      
      =
      
        True)



            
      
      
        #
      
      
         exception message is printed to all logs
      
      
                    LOG.critical(e)

            sys.exit(
      
      1
      
        )

    
      
      
        return
      
      
         wrapper

...
      
    

  至此,我們從WSGI和paste-deploy的角度邁出了深入了解keystone實現(xiàn)的第一步,知道了keystone服務器是如何將一個HTTP請求粗略地歸類分發(fā)到pipeline,再通過filter到達相應的app。下一步,我們將會看到每一個pipeline末端的app如何針對具體的HTTP請求方法和地址將其分發(fā)到對應的router,router再將其交給相應的controller,由controller承上啟下完成最終的工作的。

keystone源碼分析(一)——Paste Deploy的應用


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。?!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲在线久久 | 免费毛片a| 99在线免费播放 | www四虎在线高清 | 亚洲视频 中文字幕 | 日韩xoxo视频在线观看 | 日韩中文字幕在线亚洲一区 | 天天靠天天擦天天摸 | 精品亚洲一区二区三区 | 日韩精品福利视频一区二区三区 | 日韩a免费 | 99r视频 | 伊人国产在线观看 | 爱爱夜夜爽成人夜夜爽 | 日日私人影院 | 国产精品久久久久999 | 日韩欧美一级毛片视频免费 | 亚洲国产精品一区二区久久 | 亚洲日韩成人 | 日本猛妇色xxxxx在线 | 日韩专区中文字幕 | 成人毛片网 | 不卡一级毛片免费高清 | 一区二区三区中文字幕 | 久久亚洲国产中v天仙www | 免费看欧美一级特黄a毛片 免费看欧美一级特黄α大片 | 四虎影院一级片 | 91精品免费观看老司机 | 香蕉人人超 | 亚洲在线视频一区 | 美女被羞羞产奶视频网站 | 久久精品人 | 天天干夜夜草 | 日韩小视频 | 拍真实国产伦偷精品 | 奇米777影视成人四色 | 欧美午夜久久 | 亚洲免费资源 | 亚洲高清中文字幕一区二区三区 | h片免费观看 | 欧美操操操 |