File size: 6,915 Bytes
4a701b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env python
#
# Copyright 2013 Google Inc. All Rights Reserved.
#

"""A convenience wrapper for starting gsutil."""

from __future__ import absolute_import
from __future__ import unicode_literals

import json
import os


import bootstrapping
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.core import config
from googlecloudsdk.core import context_aware
from googlecloudsdk.core import log
from googlecloudsdk.core import metrics
from googlecloudsdk.core import properties
from googlecloudsdk.core.credentials import gce as c_gce
from googlecloudsdk.core.util import encoding
from googlecloudsdk.core.util import files


def _MaybeAddBotoOption(args, section, name, value):
  if value is None:
    return
  args.append('-o')
  args.append('{section}:{name}={value}'.format(
      section=section, name=name, value=value))


def _GetCertProviderCommand(context_config):
  """Returns the cert provider command from the context config."""
  # TODO(b/190102217) - Cleanup code that handles both version of context_config
  if hasattr(context_config, 'cert_provider_command'):
    return context_config.cert_provider_command

  try:
    contents = files.ReadFileContents(context_config.config_path)
    json_out = json.loads(contents)
    if 'cert_provider_command' in json_out:
      return json_out['cert_provider_command']
  except files.Error as e:
    log.debug('context aware settings discovery file %s - %s',
              context_config.config_path, e)


def _AddContextAwareOptions(args):
  """Adds device certificate settings for mTLS."""
  context_config = context_aware.Config()
  # Enterprise certificate is not yet supported for gsutil.
  if (
      context_config
      and context_config.config_type
      == context_aware.ConfigType.ENTERPRISE_CERTIFICATE
  ):
    return

  # TODO(b/190102217) - Cleanup code that handles both version of context_config
  use_client_certificate = (
      context_config and
      getattr(context_config, 'use_client_certificate', True))
  _MaybeAddBotoOption(args, 'Credentials', 'use_client_certificate',
                      use_client_certificate)
  if context_config:
    cert_provider_command = _GetCertProviderCommand(context_config)
    if isinstance(cert_provider_command, list):
      # e.g. cert_provider_command = ['*/apihelper', '--print_certificate']
      cert_provider_command = ' '.join(cert_provider_command)
    # Don't need to pass mTLS data if gsutil shouldn't be using it.
    _MaybeAddBotoOption(args, 'Credentials', 'cert_provider_command',
                        cert_provider_command)


def main():
  """Launches gsutil."""

  args = []

  project, account = bootstrapping.GetActiveProjectAndAccount()
  pass_credentials = (
      properties.VALUES.core.pass_credentials_to_gsutil.GetBool() and
      not properties.VALUES.auth.disable_credentials.GetBool())

  _MaybeAddBotoOption(args, 'GSUtil', 'default_project_id', project)

  if pass_credentials:
    # Allow gsutil to only check for the '1' string value, as is done
    # with regard to the 'CLOUDSDK_WRAPPER' environment variable.
    encoding.SetEncodedValue(
        os.environ, 'CLOUDSDK_CORE_PASS_CREDENTIALS_TO_GSUTIL', '1')

    if account in c_gce.Metadata().Accounts():
      # Tell gsutil that it should obtain credentials from the GCE metadata
      # server for the instance's configured service account.
      _MaybeAddBotoOption(args, 'GoogleCompute', 'service_account', 'default')
      # For auth'n debugging purposes, allow gsutil to reason about whether the
      # configured service account was set in a boto file or passed from here.
      encoding.SetEncodedValue(
          os.environ, 'CLOUDSDK_PASSED_GCE_SERVICE_ACCOUNT_TO_GSUTIL', '1')
    else:
      legacy_config_path = config.Paths().LegacyCredentialsGSUtilPath(account)
      # We construct a BOTO_PATH that tacks the config containing our
      # credentials options onto the end of the list of config paths. We ensure
      # the other credential options are loaded first so that ours will take
      # precedence and overwrite them.
      boto_config = encoding.GetEncodedValue(os.environ, 'BOTO_CONFIG', '')
      boto_path = encoding.GetEncodedValue(os.environ, 'BOTO_PATH', '')
      if boto_config:
        boto_path = os.pathsep.join([boto_config, legacy_config_path])
      elif boto_path:
        boto_path = os.pathsep.join([boto_path, legacy_config_path])
      else:
        path_parts = ['/etc/boto.cfg',
                      os.path.expanduser(os.path.join('~', '.boto')),
                      legacy_config_path]
        boto_path = os.pathsep.join(path_parts)

      encoding.SetEncodedValue(os.environ, 'BOTO_CONFIG', None)
      encoding.SetEncodedValue(os.environ, 'BOTO_PATH', boto_path)

  # Tell gsutil whether gcloud analytics collection is enabled.
  encoding.SetEncodedValue(
      os.environ, 'GA_CID', metrics.GetCIDIfMetricsEnabled())

  # Set proxy settings. Note that if these proxy settings are configured in a
  # boto config file, the options here will be loaded afterward, overriding
  # them.
  proxy_params = properties.VALUES.proxy
  proxy_address = proxy_params.address.Get()
  if proxy_address:
    _MaybeAddBotoOption(args, 'Boto', 'proxy', proxy_address)
    _MaybeAddBotoOption(args, 'Boto', 'proxy_port', proxy_params.port.Get())
    _MaybeAddBotoOption(args, 'Boto', 'proxy_rdns', proxy_params.rdns.GetBool())
    _MaybeAddBotoOption(args, 'Boto', 'proxy_user', proxy_params.username.Get())
    _MaybeAddBotoOption(args, 'Boto', 'proxy_pass', proxy_params.password.Get())

  # Set SSL-related settings.
  disable_ssl = properties.VALUES.auth.disable_ssl_validation.GetBool()
  _MaybeAddBotoOption(args, 'Boto', 'https_validate_certificates',
                      None if disable_ssl is None else not disable_ssl)
  _MaybeAddBotoOption(args, 'Boto', 'ca_certificates_file',
                      properties.VALUES.core.custom_ca_certs_file.Get())

  # Sync device certificate settings for mTLS.
  _AddContextAwareOptions(args)

  # Note that the original args to gsutil will be appended after the args we've
  # supplied here.
  bootstrapping.ExecutePythonTool('platform/gsutil', 'gsutil', *args)


if __name__ == '__main__':
  try:
    version = bootstrapping.ReadFileContents('platform/gsutil', 'VERSION')
    bootstrapping.CommandStart('gsutil', version=version)

    blocked_commands = {
        'update': 'To update, run: gcloud components update',
    }

    argv = bootstrapping.GetDecodedArgv()
    bootstrapping.WarnAndExitOnBlockedCommand(argv, blocked_commands)

    # Don't call bootstrapping.PreRunChecks because anonymous access is
    # supported for some endpoints. gsutil will output the appropriate
    # error message upon receiving an authentication error.
    bootstrapping.CheckUpdates('gsutil')
    main()
  except Exception as e:  # pylint: disable=broad-except
    exceptions.HandleError(e, 'gsutil')