Observação:
- Este tutorial requer acesso ao Oracle Cloud. Para se inscrever em uma conta gratuita, consulte Conceitos básicos do Oracle Cloud Infrastructure Free Tier.
- Ele usa valores de exemplo para credenciais, tenancy e compartimentos do Oracle Cloud Infrastructure. Ao concluir seu laboratório, substitua esses valores por valores específicos do seu ambiente de nuvem.
Excluir Usuários Inativos dos Domínios de Identidade do OCI IAM com Base em UserStatus e LastSuccessfulLoginDate Usando o Python
Introdução
A Oracle Cloud Infrastructure (OCI) é uma plataforma de nuvem capaz de fornecer uma variedade de serviços de nuvem, incluindo armazenamento, rede e infraestrutura. O Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) é um serviço que permite gerenciar o acesso aos recursos do OCI. Ele fornece autenticação e autorização para usuários e grupos.
A exclusão de usuários inativos com base em sua última data de log-in bem-sucedida nos Domínios de Identidade do OCI IAM pode ser particularmente útil no contexto do modelo de preços por usuário do OCI por vários motivos:
-
Otimização de Custos: O OCI segue um modelo de preços por usuário, o que significa que você é cobrado por cada conta de usuário. Ao identificar e excluir regularmente usuários inativos, você pode reduzir significativamente seus custos de assinatura. Essa otimização de custos se torna ainda mais crítica à medida que sua organização aumenta e o número de usuários aumenta.
-
Aprimoramento de Segurança: Contas de usuário inativas são um risco potencial de segurança. Essas contas podem não ser mais usadas por usuários legítimos, mas ainda podem ser exploradas por agentes maliciosos se não forem atendidas. A exclusão de usuários inativos garante que apenas indivíduos autorizados tenham acesso aos seus recursos do OCI, reduzindo a superfície de ataque e aprimorando a segurança geral.
-
Resource Management: Gerenciar um grande número de contas de usuário inativas pode ser uma tarefa administrativa. Ele desorganiza seu ambiente IAM e dificulta o foco em contas de usuário ativas. Automatizar o processo de identificação e exclusão de usuários inativos libera recursos administrativos e permite que sua equipe se concentre em tarefas mais estratégicas.
-
Conformidade: Os padrões de conformidade geralmente exigem que as organizações revisem e gerenciem regularmente contas de usuários. A exclusão de usuários inativos pode ajudá-lo a atender aos requisitos de conformidade e demonstrar um compromisso com a segurança e a governança de dados.
Para implementar esse processo de forma eficaz, o trecho de código abaixo do python pode ser usado para automatizar a identificação e a exclusão de usuários inativos com base na última data de login bem-sucedida e no status ativo/inativo. Ao executar regularmente esses scripts, você pode manter um ambiente IAM enxuto e seguro enquanto otimiza seus custos no OCI.
Público-alvo
Profissionais e administradores de IAM.
Objetivo
Exclua usuários com base no status do usuário e lastSuccessfulLoginDate dos Domínios de Identidade do OCI IAM usando a API REST com Python.
Pré-requisitos
-
Uma assinatura ativa do OCI.
-
Familiarizado com OCI IAM e Python.
-
É necessário conhecimento do uso da API REST de Domínios de Identidade do OCI IAM.
-
Um usuário do IAM com autorização para gerenciar Aplicativos (Administrador de Domínio de Identidades, Administrador de Segurança ou Administrador de Aplicativos).
-
Python 3.x instalado no seu sistema.
-
Pacotes Python
urllib3
,requests
edatetime
instalados.
Tarefa 1: Criar um aplicativo confidencial nos Domínios de Identidade do OCI IAM
Siga o Oracle Identity Cloud Service: Primeira Chamada de API REST para criar um aplicativo confidencial e recuperar o ID do cliente e o segredo do cliente, que podem ser usados para executar uma chamada de API REST para o OCI IAM para recuperar o Token de Acesso e pontos finais de API subsequentes.
Tarefa 2: Configurar o arquivo config.json
Configure o arquivo de configuração em sua máquina local. O arquivo config.json
tem informações sobre o URL do Domínio de Identidades, o ID do Cliente e o Segredo do Cliente que é usado para gerar o Token de Acesso.
{
"iamurl" : "https://idcs-###########.identity.oraclecloud.com",
"client_id" : "#######################",
"client_secret" : "#######################"
}
Tarefa 3: Obter o Token de Acesso
Depois que o arquivo config.json
estiver em vigor, a primeira coisa que você precisa fazer é gerar o Token de Acesso, que pode ser usado para fazer chamadas adicionais da API REST para os pontos finais do OCI IAM.
No trecho de código abaixo, a função get_encoded usa o ID do Cliente e o Segredo do Cliente como argumentos e retorna a string base64-encoded
. Essa string codificada é posteriormente passada como um argumento para a função get_access_token
como um cabeçalho de Autorização, para obter o Token de Acesso executando uma solicitação POST.
#get base64 encoded
def get_encoded(self,clid, clsecret):
encoded = clid + ":" + clsecret
baseencoded = base64.urlsafe_b64encode(encoded.encode('UTF-8')).decode('ascii')
return baseencoded
#get access token
def get_access_token(self,url, header):
para = "grant_type=client_credentials&scope=urn:opc:idm:__myscopes__"
response = requests.post(url, headers=header, data=para, verify=False)
jsonresp = json.loads(response.content)
access_token = jsonresp.get('access_token')
return access_token
#print access token
def printaccesstoken(self):
obj = IAM()
encodedtoken = obj.get_encoded(clientID, clientSecret)
extra = "/oauth2/v1/token"
headers = {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'Authorization': 'Basic %s' % encodedtoken, 'Accept': '*/*'}
accesstoken = obj.get_access_token(idcsURL + extra, headers)
return accesstoken
Tarefa 4: Tratar um lote de informações do usuário (lastSuccessfulLoginDate, userStatus) para limpar usuários
Temos o token de acesso, usando o qual podemos fazer mais chamadas de API REST para diferentes pontos finais REST de Domínios de Identidade do OCI IAM. O trecho de código abaixo mostra como estamos fazendo uma solicitação GET com cabeçalhos e parâmetros necessários para o ponto final /admin/v1/Users
, a fim de recuperar o número total de usuários e calcular o número de iterações necessárias, com base no número total de resultados e na contagem por solicitação.
-
A função obtém a data atual no formato AAAA-MM-DD e armazena em uma variável
current_date
e, em seguida, repete os dados de cada usuário. -
Em cada iteração, ele envia uma solicitação GET com os parâmetros apropriados para recuperar um batch de informações do usuário (nome de usuário, lastSuccessfulLoginDate e ativo) e, em seguida, executa algumas verificações condicionais.
-
O código então, com base em verificações condicionais definidas, anexa o nome de usuário e o id de usuário de todos os usuários correspondentes nos arquivos
username.txt
euserid.txt
, respectivamente, e o marca para exclusão. Primeiro, ele verifica o status do usuário e, se for Falso (que significa inativo), anexa o usuário aos arquivostxt
e continua para a próxima iteração do loop. Em seguida, ele verifica o estado do usuário e, se for Nenhum, imprime que _{user} nunca acessou. Tome uma decisão de excluí-la manualmente no console e prossiga para a próxima iteração do loop. -
O script recupera a data do último log-in bem-sucedido do usuário, calcula o número de dias desde o último log-in e imprime-o no console. Para qualquer usuário que não tenha feito login por mais de 90 dias, o script verifica se o usuário tem funções administrativas específicas associadas a ele. Qualquer usuário que não tenha Conectado por 90 dias e tenha NÃO atribuições administrativas será identificado e marcado para exclusão.
-
Depois de processar todos os usuários, um conjunto de IDs de usuário a ser excluído é gravado em um arquivo JSON
username.json
. Uma solicitação de exclusão em massa é preparada formatando os dados em um formato JSON específico. A solicitação de exclusão em massa é enviada ao ponto final/admin/v1/Bulk
e uma mensagem é impressa para indicar que os usuários identificados foram excluídos. -
Depois de todas as iterações, a função retorna à função principal.
Observação: há uma seção de código comentada com explicações para ações futuras ou decisões manuais, como lidar com usuários que nunca acessaram o sistema. Pode haver um cenário em que um Administrador talvez não tenha acessado o OCI IAM e talvez você não queira excluí-los.
def get_successfullogindate(self): extra = "/admin/v1/Users" obj = IAM() accesstoken = obj.printaccesstoken() headers = {'Authorization': 'Bearer ' + accesstoken} resp = requests.get(idcsURL+extra, headers=headers, verify=False) jsonresp = json.loads(resp.content) totalCount = jsonresp.get("totalResults") print("Total number of users: " + str(totalCount)) current_date = datetime.now().date() startIndex = 1 count = 50 loop = int(totalCount / count) extra2 = "/admin/v1/AppRoles" for i in range(loop + 1): param = { 'attributes': "username,active,urn:ietf:params:scim:schemas:oracle:idcs:extension:userState:User:lastSuccessfulLoginDate", 'startIndex': startIndex, 'count': count} resp = requests.get(idcsURL+extra, headers=headers, verify=False, params=param) startIndex += count jsonresp = json.loads(resp.content) tempjsn = jsonresp.get("Resources") for x in tempjsn: trimjsn = {} username = trimjsn['userName'] = x.get("userName") userid = x.get("id") userStatus = x.get("active") userState = x.get("urn:ietf:params:scim:schemas:oracle:idcs:extension:userState:User") if userStatus is False: print(username + " is in inactive state. Will be deleted.") with open('username.txt', 'a') as c: c.write(username) c.write('\n') with open('userID.txt', 'a') as d: d.write(userid) d.write('\n') continue if userState is None: print(username + " has never accessed. Kindly make a decision to delete it manually on console") # with open('username.txt', 'a') as c: # c.write(username) # c.write('\n') # with open('userID.txt', 'a') as d: # d.write(userid) # d.write('\n') # ** Uncomment the lines commented above to delete the users who have never accessed ** continue lastLoginDate = x['urn:ietf:params:scim:schemas:oracle:idcs:extension:userState:User']['lastSuccessfulLoginDate'] target_dates = datetime.strptime(lastLoginDate, '%Y-%m-%dT%H:%M:%S.%fZ').date() num_days = (current_date - target_dates).days #print(username + " Last logged in " + str(num_days) + " days ago") if num_days > 30: #print("entered if condition for more than 90 days ") params2 = {"filter": f'members[value eq "{userid}"] and app.value eq "IDCSAppId" and (displayName eq "Identity Domain Administrator" or displayName eq "Security Administrator" or displayName eq "Application Administrator" or displayName eq "User Administrator" or displayName eq "User Manager" or displayName eq "Help Desk Administrator" or displayName eq "Audit Administrator")'} resp2 = requests.get(idcsURL+extra2, headers=headers, verify=False, params=params2) jsonresp3 = json.loads(resp2.content) totalCount1 = jsonresp3.get("totalResults") if totalCount1 < 1: print(username + " has not Logged in for 90 days and has NO admin role. Will be deleted.") with open('username.txt', 'a') as c: c.write(username) c.write('\n') with open('userID.txt', 'a') as d: d.write(userid) d.write('\n') try: with open('userID.txt','r') as g: lines = len(g.readlines()) except FileNotFoundError: print("No users found to be Deleted by the Script") exit() x=0 while x<lines: with open('userID.txt','r') as e: content = e.readlines() id=content[x] id=id.rstrip(id[-1]) paradelete=json.dumps( { "method": "DELETE", "path": "/Users/"+id+"?forceDelete=true" } ) with open('username.json', 'a') as j: j.writelines(paradelete) j.write(',') x=x+1 with open('username.json', 'r') as file: data = file.read() with open('formatedData.json', 'a') as file1: file1.writelines('{ \n') file1.writelines('"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],\n') file1.writelines('"Operations": [\n') data2=data.rstrip(data[-1]) file1.write(data2) file1.write(']}') headers = {'Authorization': 'Bearer ' + accesstoken} bulkdata = json.load(open('formatedData.json')) param = {'forceDelete': True} payload = json.dumps(bulkdata) headers2 = {'Content-Type': 'application/json','Authorization': 'Bearer ' + accesstoken, 'Accept': '*/*'} extra2="/admin/v1/Bulk" #respdelete = requests.request("POST",idcsURL + extra2, headers=headers2, verify=False, params=param,data=payload) print("The identified users has been deleted ") try: os.remove('userID.txt') os.remove('username.txt') os.remove('formatedData.json') os.remove('username.json') except FileNotFoundError: exit()
Tarefa 5: Usar o script no OCI Cloud Shell
Depois que o script estiver pronto, ele poderá ser facilmente executado na máquina local (com o Python Instalado) ou em qualquer IDE que suporte o desenvolvimento do Python. Estamos usando o OCI Cloud Shell para executar o script e obter o relatório desejado.
-
Faça log-in na Console do OCI, abra o Cloud Shell no canto superior direito da tela e faça upload do script Python e do arquivo
config.json
. -
Execute
python DeleteUser_PriorCheck_InactivePeriod60days_IsAdmin.py
.Observação:
DeleteUser_PriorCheck_InactivePeriod60days_IsAdmin.py
é o script Python desenvolvido usando trechos de código acima.
Links Relacionados
Agradecimentos
-
Autor - Gautam Mishra (Engenheiro Sênior de Nuvem)
-
Colaborador - Chetan Soni (Engenheiro de Soluções em Nuvem)
Mais Recursos de Aprendizagem
Explore outros laboratórios em docs.oracle.com/learn ou acesse mais conteúdo de aprendizado gratuito no canal Oracle Learning YouTube. Além disso, visite education.oracle.com/learning-explorer para se tornar um Oracle Learning Explorer.
Para obter a documentação do produto, visite o Oracle Help Center.
Delete Inactive Users from OCI IAM Identity Domains Based on UserStatus and LastSuccessfulLoginDate Using Python
F89514-01
November 2023
Copyright © 2023, Oracle and/or its affiliates.