1package awsec2
2
3import (
4	"fmt"
5
6	"github.com/fatih/structs"
7	"github.com/hashicorp/vault/logical"
8	"github.com/hashicorp/vault/logical/framework"
9)
10
11const (
12	roletagBlacklistConfigPath = "config/tidy/roletag-blacklist"
13)
14
15func pathConfigTidyRoletagBlacklist(b *backend) *framework.Path {
16	return &framework.Path{
17		Pattern: fmt.Sprintf("%s$", roletagBlacklistConfigPath),
18		Fields: map[string]*framework.FieldSchema{
19			"safety_buffer": &framework.FieldSchema{
20				Type:    framework.TypeDurationSecond,
21				Default: 15552000, //180d
22				Description: `The amount of extra time that must have passed beyond the roletag
23expiration, before it is removed from the backend storage.
24Defaults to 4320h (180 days).`,
25			},
26
27			"disable_periodic_tidy": &framework.FieldSchema{
28				Type:        framework.TypeBool,
29				Default:     false,
30				Description: "If set to 'true', disables the periodic tidying of blacklisted entries.",
31			},
32		},
33
34		ExistenceCheck: b.pathConfigTidyRoletagBlacklistExistenceCheck,
35
36		Callbacks: map[logical.Operation]framework.OperationFunc{
37			logical.CreateOperation: b.pathConfigTidyRoletagBlacklistCreateUpdate,
38			logical.UpdateOperation: b.pathConfigTidyRoletagBlacklistCreateUpdate,
39			logical.ReadOperation:   b.pathConfigTidyRoletagBlacklistRead,
40			logical.DeleteOperation: b.pathConfigTidyRoletagBlacklistDelete,
41		},
42
43		HelpSynopsis:    pathConfigTidyRoletagBlacklistHelpSyn,
44		HelpDescription: pathConfigTidyRoletagBlacklistHelpDesc,
45	}
46}
47
48func (b *backend) pathConfigTidyRoletagBlacklistExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) {
49	entry, err := b.lockedConfigTidyRoleTags(req.Storage)
50	if err != nil {
51		return false, err
52	}
53	return entry != nil, nil
54}
55
56func (b *backend) lockedConfigTidyRoleTags(s logical.Storage) (*tidyBlacklistRoleTagConfig, error) {
57	b.configMutex.RLock()
58	defer b.configMutex.RUnlock()
59
60	return b.nonLockedConfigTidyRoleTags(s)
61}
62
63func (b *backend) nonLockedConfigTidyRoleTags(s logical.Storage) (*tidyBlacklistRoleTagConfig, error) {
64	entry, err := s.Get(roletagBlacklistConfigPath)
65	if err != nil {
66		return nil, err
67	}
68	if entry == nil {
69		return nil, nil
70	}
71
72	var result tidyBlacklistRoleTagConfig
73	if err := entry.DecodeJSON(&result); err != nil {
74		return nil, err
75	}
76
77	return &result, nil
78}
79
80func (b *backend) pathConfigTidyRoletagBlacklistCreateUpdate(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
81	b.configMutex.Lock()
82	defer b.configMutex.Unlock()
83
84	configEntry, err := b.nonLockedConfigTidyRoleTags(req.Storage)
85	if err != nil {
86		return nil, err
87	}
88	if configEntry == nil {
89		configEntry = &tidyBlacklistRoleTagConfig{}
90	}
91	safetyBufferInt, ok := data.GetOk("safety_buffer")
92	if ok {
93		configEntry.SafetyBuffer = safetyBufferInt.(int)
94	} else if req.Operation == logical.CreateOperation {
95		configEntry.SafetyBuffer = data.Get("safety_buffer").(int)
96	}
97	disablePeriodicTidyBool, ok := data.GetOk("disable_periodic_tidy")
98	if ok {
99		configEntry.DisablePeriodicTidy = disablePeriodicTidyBool.(bool)
100	} else if req.Operation == logical.CreateOperation {
101		configEntry.DisablePeriodicTidy = data.Get("disable_periodic_tidy").(bool)
102	}
103
104	entry, err := logical.StorageEntryJSON(roletagBlacklistConfigPath, configEntry)
105	if err != nil {
106		return nil, err
107	}
108
109	if err := req.Storage.Put(entry); err != nil {
110		return nil, err
111	}
112
113	return nil, nil
114}
115
116func (b *backend) pathConfigTidyRoletagBlacklistRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
117	clientConfig, err := b.lockedConfigTidyRoleTags(req.Storage)
118	if err != nil {
119		return nil, err
120	}
121	if clientConfig == nil {
122		return nil, nil
123	}
124
125	return &logical.Response{
126		Data: structs.New(clientConfig).Map(),
127	}, nil
128}
129
130func (b *backend) pathConfigTidyRoletagBlacklistDelete(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
131	b.configMutex.Lock()
132	defer b.configMutex.Unlock()
133
134	return nil, req.Storage.Delete(roletagBlacklistConfigPath)
135}
136
137type tidyBlacklistRoleTagConfig struct {
138	SafetyBuffer        int  `json:"safety_buffer" structs:"safety_buffer" mapstructure:"safety_buffer"`
139	DisablePeriodicTidy bool `json:"disable_periodic_tidy" structs:"disable_periodic_tidy" mapstructure:"disable_periodic_tidy"`
140}
141
142const pathConfigTidyRoletagBlacklistHelpSyn = `
143Configures the periodic tidying operation of the blacklisted role tag entries.
144`
145const pathConfigTidyRoletagBlacklistHelpDesc = `
146By default, the expired entries in the blacklist will be attempted to be removed
147periodically. This operation will look for expired items in the list and purges them.
148However, there is a safety buffer duration (defaults to 72h), purges the entries
149only if they have been persisting this duration, past its expiration time.
150`
151