Uploaded image for project: 'Mesos'
  1. Mesos
  2. MESOS-8283

Operator API `SUBSCRIBE` call doesn't fully respect acls

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Major
    • Resolution: Invalid
    • Affects Version/s: 1.4.0
    • Fix Version/s: None
    • Component/s: HTTP API, master
    • Labels:

      Description

      When an operator subscribes to the event stream using the SUBSCRIBE call, the initial response is properly authorized (with filter in the state). The same holds true for the events TASK_ADDED and TASK_UPDATED which, if a user has no right to see them he won't receive the updates, AGENT_ADDED seems to be respected too. However any user will get FRAMEWORK_ADDED and FRAMEWORK_UPDATED events.

      I didn't AGENT_REMOVED

      In order to test I used the following acls:

      {
        "permissive": true,
        "view_roles" : [
         {
           "principals" : { "type" : "ANY" },
           "roles" : { "values" : ["*"] }
         },
         {
           "principals" : { "values" : ["hal-9000"] },
           "roles" : { "type" : "ANY" }
         },
         {
           "principals" : { "values" : ["glados"] },
           "roles" : { "type" : "NONE" }
         }
        ],
        "view_framework": [
         {
           "principals" : { "values" : ["hal-9000"] },
           "users" : { "type" : "ANY" }
         },
         {
           "principals" : { "values" : ["glados"] },
           "users" : { "type" : "NONE" }
         }
        ],
        "view_tasks": [
         {
           "principals" : { "values" : ["hal-9000"] },
           "users" : { "type" : "ANY" }
         },
         {
           "principals" : { "values" : ["glados"] },
           "users" : { "type" : "NONE" }
         }
        ],
        "register_agent": [
         {
           "principals" : { "values" : ["hal-9000"] },
           "users" : { "type" : "ANY" }
         },
         {
           "principals" : { "values" : ["glados"] },
           "users" : { "type" : "NONE" }
         }
        ]
      }
      

      the following credential files:

      super super
      hal-9000 hal-9000
      glados glados
      

      And launch a master and an agent as follows:

      ./mesos-master.sh \
        --work_dir=/tmp/$USER/mesos/master \
        --log_dir=/tmp/$USER/mesos/master/log \
        --ip=${MASTER_IP} \
        --agent_ping_timeout=5secs \
        --max_agent_ping_timeouts=2 \
        --agent_removal_rate_limit=1/1secs \
        --http_framework_authenticators=basic \
        --authenticate_http \
        --authenticate_http_frameworks \
        --acls=$HOME/testing/acls.json \
        --credentials=$HOME/testing/credentials.txt
      
      sudo ./mesos-agent.sh \
           --work_dir=/tmp/$USER/mesos/agent \
           --log_dir=/tmp/$USER/mesos/agent/log \
           --containerizers=mesos,docker \
           --master=${MASTER_IP}:5050 \
           --authenticate_http_readwrite \
           --http_authenticators=basic \
           --acls=$HOME/Documents/workspace/testing/acls.json \
           --http_credentials=$HOME/testing/credentials.txt
      

      Once the master and agent are running, use the following script (user this recordio file):

      #! /usr/bin/env python3
      
      import json
      import recordio
      import requests
      import sys
      
      from contextlib import closing
      from typing import Dict
      
      MACHINE_NAME='ip.to.machine'
      MACHINE_IP='ip.to.machine'
      
      def test_mesos_v1_master_subscribe(host: str, ip: str) -> None:
          base_url = 'http://{}:5050'.format(host)
      
          headers = {
              'Content-Type': 'application/json',
              'Accept': 'application/json',
              'Connection': 'close',
          }
      
          decoder = recordio.Decoder(lambda s: json.loads(s.decode("UTF-8")))
      
          with closing(requests.post(
                  base_url + '/api/v1',
                  json={'type': 'SUBSCRIBE'},
                  auth=('hal-9000', 'hal-9000'),
                  headers=headers,
                  stream=True,
          )) as response:
              assert response.status_code == 200, response.text
              chunks = response.iter_content(chunk_size=None)
              events = []  # type: ignore
              for chunk in chunks:
                  for record in decoder.decode(chunk):
                      if record['type'] != 'HEARTBEAT':
                          print('got event "' + record['type'])
                          events.append(record['type'])
                  # It takes at least 10 mins for an agent to be marked as gone.
                  if len(events) >= 7:
                      print('got the following events "' + '", "'.join(events) + '"')
                      break
      
          with closing(requests.post(
                  base_url + '/api/v1',
                  json={'type': 'SUBSCRIBE'},
                  auth=('glados', 'glados'),
                  headers=headers,
                  stream=True,
          )) as response:
              assert response.status_code == 200, response.text
              chunks = response.iter_content(chunk_size=None)
              for chunk in chunks:
                  for record in decoder.decode(chunk):
                      if record['type'] not in ('HEARTBEAT', 'SUBSCRIBED'):
                          print('It wasn\'t supposed to get "' + record['type'] + '"')
      
      def main(args: Dict[str, str]) -> None:
          test_mesos_v1_master_subscribe(MACHINE_NAME, MACHINE_IP)
      
      if __name__ == '__main__':
          main(sys.argv)
      

      Finally while the machine is running you do the following:

      1. Launch an extra agent:

      sudo ./mesos-agent.sh \
           --work_dir=/tmp/$USER/mesos/agent-2 \
           --log_dir=/tmp/$USER/mesos/agent-2/log \
           --containerizers=mesos,docker \
           --port=5152 \
           --master=${MASTER_IP}:5050 \
           --authenticate_http_readwrite \
           --http_authenticators=basic \
           --acls=$HOME/testing/acls.json \
           --http_credentials=$HOME/testing/credentials.txt
      

      2. Teardown the agent.
      3. Launch a framework and task:

      ./src/mesos-execute --master=${MASTER_IP}:5050 --command='while true; do echo "Hello World"; sleep 5; done;' --resources="cpus:1;mem:128;disk:32;ports:[31002-31003]" --name=hello-discovery --principal=hal-9000 --secret=hal-9000
      

      4. Teardown the framework by killing the program mesos-execute.
      5. Repeat (1) and (2).

      The output of the script is the following:

      got the following events "SUBSCRIBED", "FRAMEWORK_ADDED", "TASK_ADDED", "TASK_UPDATED", "TASK_UPDATED", "FRAMEWORK_REMOVED", "AGENT_ADDED"
      It wasn't supposed to get "FRAMEWORK_ADDED"
      It wasn't supposed to get "FRAMEWORK_REMOVED"
      

      The last two lines should not appear.

        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              arojas Alexander Rojas
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: