When displaying information from a config object add it also as cache dependency to the render array.
For example in a preprocess hook:
$config = \Drupal::config('mymodule.settings');
$config_value = $config->get('some_field');
$variables['some_field'] = [
'#markup' => $config_value,
];
// add the cache tag, so that the output gets invalidated when the config is saved
\Drupal::service('renderer')->addCacheableDependency($variables, $config);
See How to clear cache for config entity after making changes?
You don't need to change form submit because saving a config object automatically invalidates cache entries having this cache dependency (cache tag).
Another example based on the block code from your answer and using a different method to add the cache tag:
/**
* Config settings.
*
* @var string
*/
const SETTINGS = 'uw_cbl_special_alert.settings';
/**
* {@inheritdoc}
*/
public function build() {
$config = \Drupal::config(static::SETTINGS);
return [
'#markup' => $config->get('message'),
'#cache' => [
'tags' => $config->getCacheTags(),
],
];
}
Access caching
As asked in the comments, you can add cache dependencies to access results as well:
AccessResult::allowed()->addCacheableDependency($config)
AccessResult::forbidden()->addCacheableDependency($config)